Compare commits
	
		
			30 Commits
		
	
	
		
			main
			...
			feat/netwo
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 1b1d9dcdac | |||
| 2565617ff9 | |||
| 01668c7be3 | |||
| cafbc55780 | |||
| ea3c4a2d2a | |||
| 89b756a615 | |||
| 6af84bcb6d | |||
| 3c1528d879 | |||
| 6f3e7b4ae5 | |||
| 86ef57fb62 | |||
| 6c326b1fc6 | |||
| b8b10de08a | |||
| edd2dd8511 | |||
| 70ac012a83 | |||
| d5a904fe8f | |||
| b1582ab5c2 | |||
| 8a0a0289f9 | |||
| 776d029e7e | |||
| 5afb8b69bf | |||
| 65073ec1ca | |||
| 0d62e5c986 | |||
| fe5a08840c | |||
| 1c7b1cb78a | |||
| 78010c266e | |||
| ef8b04648c | |||
| d4c57c0153 | |||
| 0e198afeab | |||
| de267a9d0f | |||
| 977a2abdd7 | |||
| 91e88bbff8 | 
							
								
								
									
										484
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										484
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -1,484 +0,0 @@ | ||||
| ## Ignore Visual Studio temporary files, build results, and | ||||
| ## files generated by popular Visual Studio add-ons. | ||||
| ## | ||||
| ## Get latest from `dotnet new gitignore` | ||||
|  | ||||
| # dotenv files | ||||
| .env | ||||
|  | ||||
| # User-specific files | ||||
| *.rsuser | ||||
| *.suo | ||||
| *.user | ||||
| *.userosscache | ||||
| *.sln.docstates | ||||
|  | ||||
| # User-specific files (MonoDevelop/Xamarin Studio) | ||||
| *.userprefs | ||||
|  | ||||
| # Mono auto generated files | ||||
| mono_crash.* | ||||
|  | ||||
| # Build results | ||||
| [Dd]ebug/ | ||||
| [Dd]ebugPublic/ | ||||
| [Rr]elease/ | ||||
| [Rr]eleases/ | ||||
| x64/ | ||||
| x86/ | ||||
| [Ww][Ii][Nn]32/ | ||||
| [Aa][Rr][Mm]/ | ||||
| [Aa][Rr][Mm]64/ | ||||
| bld/ | ||||
| [Bb]in/ | ||||
| [Oo]bj/ | ||||
| [Ll]og/ | ||||
| [Ll]ogs/ | ||||
|  | ||||
| # Visual Studio 2015/2017 cache/options directory | ||||
| .vs/ | ||||
| # Uncomment if you have tasks that create the project's static files in wwwroot | ||||
| #wwwroot/ | ||||
|  | ||||
| # Visual Studio 2017 auto generated files | ||||
| Generated\ Files/ | ||||
|  | ||||
| # MSTest test Results | ||||
| [Tt]est[Rr]esult*/ | ||||
| [Bb]uild[Ll]og.* | ||||
|  | ||||
| # NUnit | ||||
| *.VisualState.xml | ||||
| TestResult.xml | ||||
| nunit-*.xml | ||||
|  | ||||
| # Build Results of an ATL Project | ||||
| [Dd]ebugPS/ | ||||
| [Rr]eleasePS/ | ||||
| dlldata.c | ||||
|  | ||||
| # Benchmark Results | ||||
| BenchmarkDotNet.Artifacts/ | ||||
|  | ||||
| # .NET | ||||
| project.lock.json | ||||
| project.fragment.lock.json | ||||
| artifacts/ | ||||
|  | ||||
| # Tye | ||||
| .tye/ | ||||
|  | ||||
| # ASP.NET Scaffolding | ||||
| ScaffoldingReadMe.txt | ||||
|  | ||||
| # StyleCop | ||||
| StyleCopReport.xml | ||||
|  | ||||
| # Files built by Visual Studio | ||||
| *_i.c | ||||
| *_p.c | ||||
| *_h.h | ||||
| *.ilk | ||||
| *.meta | ||||
| *.obj | ||||
| *.iobj | ||||
| *.pch | ||||
| *.pdb | ||||
| *.ipdb | ||||
| *.pgc | ||||
| *.pgd | ||||
| *.rsp | ||||
| *.sbr | ||||
| *.tlb | ||||
| *.tli | ||||
| *.tlh | ||||
| *.tmp | ||||
| *.tmp_proj | ||||
| *_wpftmp.csproj | ||||
| *.log | ||||
| *.tlog | ||||
| *.vspscc | ||||
| *.vssscc | ||||
| .builds | ||||
| *.pidb | ||||
| *.svclog | ||||
| *.scc | ||||
|  | ||||
| # Chutzpah Test files | ||||
| _Chutzpah* | ||||
|  | ||||
| # Visual C++ cache files | ||||
| ipch/ | ||||
| *.aps | ||||
| *.ncb | ||||
| *.opendb | ||||
| *.opensdf | ||||
| *.sdf | ||||
| *.cachefile | ||||
| *.VC.db | ||||
| *.VC.VC.opendb | ||||
|  | ||||
| # Visual Studio profiler | ||||
| *.psess | ||||
| *.vsp | ||||
| *.vspx | ||||
| *.sap | ||||
|  | ||||
| # Visual Studio Trace Files | ||||
| *.e2e | ||||
|  | ||||
| # TFS 2012 Local Workspace | ||||
| $tf/ | ||||
|  | ||||
| # Guidance Automation Toolkit | ||||
| *.gpState | ||||
|  | ||||
| # ReSharper is a .NET coding add-in | ||||
| _ReSharper*/ | ||||
| *.[Rr]e[Ss]harper | ||||
| *.DotSettings.user | ||||
|  | ||||
| # TeamCity is a build add-in | ||||
| _TeamCity* | ||||
|  | ||||
| # DotCover is a Code Coverage Tool | ||||
| *.dotCover | ||||
|  | ||||
| # AxoCover is a Code Coverage Tool | ||||
| .axoCover/* | ||||
| !.axoCover/settings.json | ||||
|  | ||||
| # Coverlet is a free, cross platform Code Coverage Tool | ||||
| coverage*.json | ||||
| coverage*.xml | ||||
| coverage*.info | ||||
|  | ||||
| # Visual Studio code coverage results | ||||
| *.coverage | ||||
| *.coveragexml | ||||
|  | ||||
| # NCrunch | ||||
| _NCrunch_* | ||||
| .*crunch*.local.xml | ||||
| nCrunchTemp_* | ||||
|  | ||||
| # MightyMoose | ||||
| *.mm.* | ||||
| AutoTest.Net/ | ||||
|  | ||||
| # Web workbench (sass) | ||||
| .sass-cache/ | ||||
|  | ||||
| # Installshield output folder | ||||
| [Ee]xpress/ | ||||
|  | ||||
| # DocProject is a documentation generator add-in | ||||
| DocProject/buildhelp/ | ||||
| DocProject/Help/*.HxT | ||||
| DocProject/Help/*.HxC | ||||
| DocProject/Help/*.hhc | ||||
| DocProject/Help/*.hhk | ||||
| DocProject/Help/*.hhp | ||||
| DocProject/Help/Html2 | ||||
| DocProject/Help/html | ||||
|  | ||||
| # Click-Once directory | ||||
| publish/ | ||||
|  | ||||
| # Publish Web Output | ||||
| *.[Pp]ublish.xml | ||||
| *.azurePubxml | ||||
| # Note: Comment the next line if you want to checkin your web deploy settings, | ||||
| # but database connection strings (with potential passwords) will be unencrypted | ||||
| *.pubxml | ||||
| *.publishproj | ||||
|  | ||||
| # Microsoft Azure Web App publish settings. Comment the next line if you want to | ||||
| # checkin your Azure Web App publish settings, but sensitive information contained | ||||
| # in these scripts will be unencrypted | ||||
| PublishScripts/ | ||||
|  | ||||
| # NuGet Packages | ||||
| *.nupkg | ||||
| # NuGet Symbol Packages | ||||
| *.snupkg | ||||
| # The packages folder can be ignored because of Package Restore | ||||
| **/[Pp]ackages/* | ||||
| # except build/, which is used as an MSBuild target. | ||||
| !**/[Pp]ackages/build/ | ||||
| # Uncomment if necessary however generally it will be regenerated when needed | ||||
| #!**/[Pp]ackages/repositories.config | ||||
| # NuGet v3's project.json files produces more ignorable files | ||||
| *.nuget.props | ||||
| *.nuget.targets | ||||
|  | ||||
| # Microsoft Azure Build Output | ||||
| csx/ | ||||
| *.build.csdef | ||||
|  | ||||
| # Microsoft Azure Emulator | ||||
| ecf/ | ||||
| rcf/ | ||||
|  | ||||
| # Windows Store app package directories and files | ||||
| AppPackages/ | ||||
| BundleArtifacts/ | ||||
| Package.StoreAssociation.xml | ||||
| _pkginfo.txt | ||||
| *.appx | ||||
| *.appxbundle | ||||
| *.appxupload | ||||
|  | ||||
| # Visual Studio cache files | ||||
| # files ending in .cache can be ignored | ||||
| *.[Cc]ache | ||||
| # but keep track of directories ending in .cache | ||||
| !?*.[Cc]ache/ | ||||
|  | ||||
| # Others | ||||
| ClientBin/ | ||||
| ~$* | ||||
| *~ | ||||
| *.dbmdl | ||||
| *.dbproj.schemaview | ||||
| *.jfm | ||||
| *.pfx | ||||
| *.publishsettings | ||||
| orleans.codegen.cs | ||||
|  | ||||
| # Including strong name files can present a security risk | ||||
| # (https://github.com/github/gitignore/pull/2483#issue-259490424) | ||||
| #*.snk | ||||
|  | ||||
| # Since there are multiple workflows, uncomment next line to ignore bower_components | ||||
| # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) | ||||
| #bower_components/ | ||||
|  | ||||
| # RIA/Silverlight projects | ||||
| Generated_Code/ | ||||
|  | ||||
| # Backup & report files from converting an old project file | ||||
| # to a newer Visual Studio version. Backup files are not needed, | ||||
| # because we have git ;-) | ||||
| _UpgradeReport_Files/ | ||||
| Backup*/ | ||||
| UpgradeLog*.XML | ||||
| UpgradeLog*.htm | ||||
| ServiceFabricBackup/ | ||||
| *.rptproj.bak | ||||
|  | ||||
| # SQL Server files | ||||
| *.mdf | ||||
| *.ldf | ||||
| *.ndf | ||||
|  | ||||
| # Business Intelligence projects | ||||
| *.rdl.data | ||||
| *.bim.layout | ||||
| *.bim_*.settings | ||||
| *.rptproj.rsuser | ||||
| *- [Bb]ackup.rdl | ||||
| *- [Bb]ackup ([0-9]).rdl | ||||
| *- [Bb]ackup ([0-9][0-9]).rdl | ||||
|  | ||||
| # Microsoft Fakes | ||||
| FakesAssemblies/ | ||||
|  | ||||
| # GhostDoc plugin setting file | ||||
| *.GhostDoc.xml | ||||
|  | ||||
| # Node.js Tools for Visual Studio | ||||
| .ntvs_analysis.dat | ||||
| node_modules/ | ||||
|  | ||||
| # Visual Studio 6 build log | ||||
| *.plg | ||||
|  | ||||
| # Visual Studio 6 workspace options file | ||||
| *.opt | ||||
|  | ||||
| # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) | ||||
| *.vbw | ||||
|  | ||||
| # Visual Studio 6 auto-generated project file (contains which files were open etc.) | ||||
| *.vbp | ||||
|  | ||||
| # Visual Studio 6 workspace and project file (working project files containing files to include in project) | ||||
| *.dsw | ||||
| *.dsp | ||||
|  | ||||
| # Visual Studio 6 technical files | ||||
| *.ncb | ||||
| *.aps | ||||
|  | ||||
| # Visual Studio LightSwitch build output | ||||
| **/*.HTMLClient/GeneratedArtifacts | ||||
| **/*.DesktopClient/GeneratedArtifacts | ||||
| **/*.DesktopClient/ModelManifest.xml | ||||
| **/*.Server/GeneratedArtifacts | ||||
| **/*.Server/ModelManifest.xml | ||||
| _Pvt_Extensions | ||||
|  | ||||
| # Paket dependency manager | ||||
| .paket/paket.exe | ||||
| paket-files/ | ||||
|  | ||||
| # FAKE - F# Make | ||||
| .fake/ | ||||
|  | ||||
| # CodeRush personal settings | ||||
| .cr/personal | ||||
|  | ||||
| # Python Tools for Visual Studio (PTVS) | ||||
| __pycache__/ | ||||
| *.pyc | ||||
|  | ||||
| # Cake - Uncomment if you are using it | ||||
| # tools/** | ||||
| # !tools/packages.config | ||||
|  | ||||
| # Tabs Studio | ||||
| *.tss | ||||
|  | ||||
| # Telerik's JustMock configuration file | ||||
| *.jmconfig | ||||
|  | ||||
| # BizTalk build output | ||||
| *.btp.cs | ||||
| *.btm.cs | ||||
| *.odx.cs | ||||
| *.xsd.cs | ||||
|  | ||||
| # OpenCover UI analysis results | ||||
| OpenCover/ | ||||
|  | ||||
| # Azure Stream Analytics local run output | ||||
| ASALocalRun/ | ||||
|  | ||||
| # MSBuild Binary and Structured Log | ||||
| *.binlog | ||||
|  | ||||
| # NVidia Nsight GPU debugger configuration file | ||||
| *.nvuser | ||||
|  | ||||
| # MFractors (Xamarin productivity tool) working folder | ||||
| .mfractor/ | ||||
|  | ||||
| # Local History for Visual Studio | ||||
| .localhistory/ | ||||
|  | ||||
| # Visual Studio History (VSHistory) files | ||||
| .vshistory/ | ||||
|  | ||||
| # BeatPulse healthcheck temp database | ||||
| healthchecksdb | ||||
|  | ||||
| # Backup folder for Package Reference Convert tool in Visual Studio 2017 | ||||
| MigrationBackup/ | ||||
|  | ||||
| # Ionide (cross platform F# VS Code tools) working folder | ||||
| .ionide/ | ||||
|  | ||||
| # Fody - auto-generated XML schema | ||||
| FodyWeavers.xsd | ||||
|  | ||||
| # VS Code files for those working on multiple tools | ||||
| .vscode/* | ||||
| !.vscode/settings.json | ||||
| !.vscode/tasks.json | ||||
| !.vscode/launch.json | ||||
| !.vscode/extensions.json | ||||
| *.code-workspace | ||||
|  | ||||
| # Local History for Visual Studio Code | ||||
| .history/ | ||||
|  | ||||
| # Windows Installer files from build outputs | ||||
| *.cab | ||||
| *.msi | ||||
| *.msix | ||||
| *.msm | ||||
| *.msp | ||||
|  | ||||
| # JetBrains Rider | ||||
| *.sln.iml | ||||
| .idea | ||||
|  | ||||
| ## | ||||
| ## Visual studio for Mac | ||||
| ## | ||||
|  | ||||
|  | ||||
| # globs | ||||
| Makefile.in | ||||
| *.userprefs | ||||
| *.usertasks | ||||
| config.make | ||||
| config.status | ||||
| aclocal.m4 | ||||
| install-sh | ||||
| autom4te.cache/ | ||||
| *.tar.gz | ||||
| tarballs/ | ||||
| test-results/ | ||||
|  | ||||
| # Mac bundle stuff | ||||
| *.dmg | ||||
| *.app | ||||
|  | ||||
| # content below from: https://github.com/github/gitignore/blob/master/Global/macOS.gitignore | ||||
| # General | ||||
| .DS_Store | ||||
| .AppleDouble | ||||
| .LSOverride | ||||
|  | ||||
| # Icon must end with two \r | ||||
| Icon | ||||
|  | ||||
|  | ||||
| # Thumbnails | ||||
| ._* | ||||
|  | ||||
| # Files that might appear in the root of a volume | ||||
| .DocumentRevisions-V100 | ||||
| .fseventsd | ||||
| .Spotlight-V100 | ||||
| .TemporaryItems | ||||
| .Trashes | ||||
| .VolumeIcon.icns | ||||
| .com.apple.timemachine.donotpresent | ||||
|  | ||||
| # Directories potentially created on remote AFP share | ||||
| .AppleDB | ||||
| .AppleDesktop | ||||
| Network Trash Folder | ||||
| Temporary Items | ||||
| .apdisk | ||||
|  | ||||
| # content below from: https://github.com/github/gitignore/blob/master/Global/Windows.gitignore | ||||
| # Windows thumbnail cache files | ||||
| Thumbs.db | ||||
| ehthumbs.db | ||||
| ehthumbs_vista.db | ||||
|  | ||||
| # Dump file | ||||
| *.stackdump | ||||
|  | ||||
| # Folder config file | ||||
| [Dd]esktop.ini | ||||
|  | ||||
| # Recycle Bin used on file shares | ||||
| $RECYCLE.BIN/ | ||||
|  | ||||
| # Windows Installer files | ||||
| *.cab | ||||
| *.msi | ||||
| *.msix | ||||
| *.msm | ||||
| *.msp | ||||
|  | ||||
| # Windows shortcuts | ||||
| *.lnk | ||||
|  | ||||
| # Vim temporary swap files | ||||
| *.swp | ||||
							
								
								
									
										81
									
								
								.vscode/launch.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										81
									
								
								.vscode/launch.json
									
									
									
									
										vendored
									
									
								
							| @@ -1,80 +1,27 @@ | ||||
| { | ||||
|   // Use IntelliSense to learn about possible attributes. | ||||
|   // Hover to view descriptions of existing attributes. | ||||
|   // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 | ||||
|   "version": "0.2.0", | ||||
|   "configurations": [ | ||||
|     { | ||||
|       "name": ".NET Launch (Client) 1", | ||||
|       "name": ".NET Core Launch (console)", | ||||
|       "type": "coreclr", | ||||
|       "request": "launch", | ||||
|       "preLaunchTask": "build-client", | ||||
|       "program": "${workspaceFolder}/Platforms/Desktop/bin/Debug/net9.0/Pong.dll", | ||||
|       "args": [], | ||||
|       "cwd": "${workspaceFolder}", | ||||
|       "stopAtEntry": false, | ||||
|       "preLaunchTask": "build", | ||||
|       // If you have changed target frameworks, make sure to update the program path. | ||||
|       "program": "${workspaceFolder}/Game/bin/Debug/net8.0/Game.dll", | ||||
|       "args": ["server"], | ||||
|       "cwd": "${workspaceFolder}/Game", | ||||
|       // For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console | ||||
|       "console": "internalConsole", | ||||
|       "justMyCode": false, | ||||
|       "logging": { | ||||
|         "moduleLoad": false, | ||||
|         "programOutput": true | ||||
|       } | ||||
|       "stopAtEntry": false | ||||
|     }, | ||||
|     { | ||||
|       "name": ".NET Launch (Client) 2", | ||||
|       "name": ".NET Core Attach", | ||||
|       "type": "coreclr", | ||||
|       "request": "launch", | ||||
|       "preLaunchTask": "build-client", | ||||
|       "program": "${workspaceFolder}/Platforms/Desktop/bin/Debug/net9.0/Desktop.dll", | ||||
|       "args": [], | ||||
|       "cwd": "${workspaceFolder}", | ||||
|       "stopAtEntry": false, | ||||
|       "console": "internalConsole", | ||||
|       "justMyCode": false, | ||||
|       "logging": { | ||||
|         "moduleLoad": false, | ||||
|         "programOutput": true | ||||
|       } | ||||
|     }, | ||||
|     { | ||||
|       "name": ".NET Launch (Server)", | ||||
|       "type": "coreclr", | ||||
|       "request": "launch", | ||||
|       "preLaunchTask": "build-server", | ||||
|       "program": "${workspaceFolder}/Platforms/Server/bin/Debug/net9.0/Server.dll", | ||||
|       "args": [], | ||||
|       "env": { | ||||
|         "PORT": "8888", | ||||
|       }, | ||||
|       "cwd": "${workspaceFolder}", | ||||
|       "stopAtEntry": false, | ||||
|       "console": "internalConsole", | ||||
|       "justMyCode": false, | ||||
|       "logging": { | ||||
|         "moduleLoad": false, | ||||
|         "programOutput": true | ||||
|       } | ||||
|     } | ||||
|   ], | ||||
|   "compounds": [ | ||||
|     { | ||||
|       "name": ".NET Launch Client & Server", | ||||
|       "configurations": [ | ||||
|         ".NET Launch (Server)", | ||||
|         ".NET Launch (Client) 1" | ||||
|       ] | ||||
|     }, | ||||
|     { | ||||
|       "name": ".NET Launch 2 Client & 1 Server", | ||||
|       "configurations": [ | ||||
|         ".NET Launch (Server)", | ||||
|         ".NET Launch (Client) 1", | ||||
|         ".NET Launch (Client) 2" | ||||
|       ] | ||||
|     }, | ||||
|     { | ||||
|       "name": ".NET Launch 2 Clients", | ||||
|       "configurations": [ | ||||
|         ".NET Launch (Client) 1", | ||||
|         ".NET Launch (Client) 2" | ||||
|       ] | ||||
|       "request": "attach", | ||||
|       "processId": "${command:pickProcess}" | ||||
|     } | ||||
|   ] | ||||
| } | ||||
|   | ||||
							
								
								
									
										7
									
								
								.vscode/settings.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								.vscode/settings.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | ||||
| { | ||||
|     "cSpell.words": [ | ||||
|         "AABB", | ||||
|         "DAABB", | ||||
|         "Syntriax" | ||||
|     ] | ||||
| } | ||||
							
								
								
									
										29
									
								
								.vscode/tasks.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										29
									
								
								.vscode/tasks.json
									
									
									
									
										vendored
									
									
								
							| @@ -2,31 +2,16 @@ | ||||
|   "version": "2.0.0", | ||||
|   "tasks": [ | ||||
|     { | ||||
|       "label": "build-client", | ||||
|       "command": "dotnet", | ||||
|       "type": "process", | ||||
|       "args": [ | ||||
|         "build", | ||||
|         "${workspaceFolder}/Platforms/Desktop" | ||||
|       ], | ||||
|       "problemMatcher": "$msCompile", | ||||
|       "group": { | ||||
|         "kind": "build", | ||||
|         "isDefault": true | ||||
|       } | ||||
|     }, | ||||
|     { | ||||
|       "label": "build-server", | ||||
|       "command": "dotnet", | ||||
|       "type": "process", | ||||
|       "args": [ | ||||
|         "build", | ||||
|         "${workspaceFolder}/Platforms/Server" | ||||
|       ], | ||||
|       "problemMatcher": "$msCompile", | ||||
|       "type": "dotnet", | ||||
|       "task": "build", | ||||
|       "problemMatcher": ["$msCompile"], | ||||
|       "group": { | ||||
|         "kind": "build", | ||||
|         "isDefault": true | ||||
|       }, | ||||
|       "label": "build", | ||||
|       "options": { | ||||
|         "cwd": "${workspaceFolder}/Game" | ||||
|       } | ||||
|     } | ||||
|   ] | ||||
|   | ||||
							
								
								
									
										16
									
								
								Dockerfile
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								Dockerfile
									
									
									
									
									
								
							| @@ -1,16 +0,0 @@ | ||||
| FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build | ||||
|  | ||||
| WORKDIR /App | ||||
| COPY . ./ | ||||
|  | ||||
| RUN dotnet restore | ||||
| RUN dotnet publish Platforms/Server -c Release -r linux-musl-x64 --self-contained true -o out | ||||
|  | ||||
| FROM alpine:latest | ||||
|  | ||||
| WORKDIR /App | ||||
| COPY --from=build /App/out . | ||||
|  | ||||
| RUN apk add --no-cache icu-libs | ||||
|  | ||||
| ENTRYPOINT ["./Server"] | ||||
							
								
								
									
										2
									
								
								Engine
									
									
									
									
									
								
							
							
								
								
								
								
								
							
						
						
									
										2
									
								
								Engine
									
									
									
									
									
								
							 Submodule Engine updated: 65dcb0c564...2cf6135063
									
								
							| @@ -3,31 +3,31 @@ | ||||
|   "isRoot": true, | ||||
|   "tools": { | ||||
|     "dotnet-mgcb": { | ||||
|       "version": "3.8.2.1105", | ||||
|       "version": "3.8.1.303", | ||||
|       "commands": [ | ||||
|         "mgcb" | ||||
|       ] | ||||
|     }, | ||||
|     "dotnet-mgcb-editor": { | ||||
|       "version": "3.8.2.1105", | ||||
|       "version": "3.8.1.303", | ||||
|       "commands": [ | ||||
|         "mgcb-editor" | ||||
|       ] | ||||
|     }, | ||||
|     "dotnet-mgcb-editor-linux": { | ||||
|       "version": "3.8.2.1105", | ||||
|       "version": "3.8.1.303", | ||||
|       "commands": [ | ||||
|         "mgcb-editor-linux" | ||||
|       ] | ||||
|     }, | ||||
|     "dotnet-mgcb-editor-windows": { | ||||
|       "version": "3.8.2.1105", | ||||
|       "version": "3.8.1.303", | ||||
|       "commands": [ | ||||
|         "mgcb-editor-windows" | ||||
|       ] | ||||
|     }, | ||||
|     "dotnet-mgcb-editor-mac": { | ||||
|       "version": "3.8.2.1105", | ||||
|       "version": "3.8.1.303", | ||||
|       "commands": [ | ||||
|         "mgcb-editor-mac" | ||||
|       ] | ||||
							
								
								
									
										0
									
								
								.dockerignore → Game/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										0
									
								
								.dockerignore → Game/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
								
								
									
										8
									
								
								Game/Abstract/IContentLoader.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								Game/Abstract/IContentLoader.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | ||||
| using Microsoft.Xna.Framework.Content; | ||||
|  | ||||
| namespace Pong.Behaviours; | ||||
|  | ||||
| public interface IMonoGameContentLoader | ||||
| { | ||||
|     void LoadContent(ContentManager content); | ||||
| } | ||||
							
								
								
									
										8
									
								
								Game/Abstract/IDisplayableShape.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								Game/Abstract/IDisplayableShape.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | ||||
| using Apos.Shapes; | ||||
|  | ||||
| namespace Syntriax.Engine.Core.Abstract; | ||||
|  | ||||
| public interface IDisplayableShape | ||||
| { | ||||
|     void Draw(ShapeBatch shapeBatch); | ||||
| } | ||||
							
								
								
									
										8
									
								
								Game/Abstract/IDisplayableSprite.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								Game/Abstract/IDisplayableSprite.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | ||||
| using Microsoft.Xna.Framework.Graphics; | ||||
|  | ||||
| namespace Syntriax.Engine.Core.Abstract; | ||||
|  | ||||
| public interface IDisplayableSprite | ||||
| { | ||||
|     public void Draw(SpriteBatch spriteBatch); | ||||
| } | ||||
							
								
								
									
										120
									
								
								Game/Behaviours/BallBehaviour.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										120
									
								
								Game/Behaviours/BallBehaviour.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,120 @@ | ||||
| using System; | ||||
|  | ||||
| using Microsoft.Xna.Framework.Audio; | ||||
| using Microsoft.Xna.Framework.Content; | ||||
|  | ||||
| using LiteNetLib; | ||||
|  | ||||
| using Syntriax.Engine.Core; | ||||
| using Syntriax.Engine.Network; | ||||
| using Syntriax.Engine.Network.Abstract; | ||||
| using Syntriax.Engine.Physics2D; | ||||
| using Syntriax.Engine.Physics2D.Abstract; | ||||
|  | ||||
| namespace Pong.Behaviours; | ||||
|  | ||||
| public class BallBehaviour : NetworkBehaviour, IMonoGameContentLoader | ||||
| { | ||||
|     public Vector2D StartDirection { get; private set; } = Vector2D.Zero; | ||||
|     public float Speed { get; set; } = 500f; | ||||
|     public float SpeedUpMultiplier { get; set; } = .0125f; | ||||
|  | ||||
|     private readonly Random random = new(); | ||||
|     private IRigidBody2D rigidBody = null!; | ||||
|     private INetworkCommunicator communicator = null!; | ||||
|     private SoundEffect soundEffect = null!; | ||||
|  | ||||
|     public void LoadContent(ContentManager content) | ||||
|     { | ||||
|         soundEffect = content.Load<SoundEffect>("Hit"); | ||||
|     } | ||||
|  | ||||
|     protected override void OnFirstActiveFrame() | ||||
|     { | ||||
|         if (!BehaviourController.TryGetBehaviour(out IRigidBody2D? foundRigidBody)) | ||||
|             throw new Exception($"{nameof(IRigidBody2D)} is missing on {GameObject.Name}."); | ||||
|         if (!BehaviourController.TryGetBehaviour(out ICollider2D? foundCollider)) | ||||
|             throw new Exception($"{nameof(ICollider2D)} is missing on {GameObject.Name}."); | ||||
|         if (!GameObject.GameManager.TryFindBehaviour(out INetworkCommunicator? foundCommunicator)) | ||||
|             throw new Exception($"{nameof(INetworkCommunicator)} is missing on GameManager."); | ||||
|  | ||||
|         foundCollider.OnCollisionDetected += OnCollisionDetected; | ||||
|  | ||||
|         rigidBody = foundRigidBody; | ||||
|         communicator = foundCommunicator; | ||||
|         if (GameObject.GameManager.TryFindBehaviour(out PongManagerBehaviour? pongManager)) | ||||
|         { | ||||
|             pongManager.OnReset += ResetBall; | ||||
|             pongManager.OnScored += ResetBall; | ||||
|             pongManager.OnFinished += DisableBall; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private void DisableBall(PongManagerBehaviour pongManager) | ||||
|     { | ||||
|         BehaviourController.GameObject.Transform.Position = Vector2D.Zero; | ||||
|         rigidBody.Velocity = Vector2D.Zero; | ||||
|     } | ||||
|  | ||||
|     private void ResetBall(PongManagerBehaviour pongManager) | ||||
|     { | ||||
|         StateEnable.Enabled = true; | ||||
|         BehaviourController.GameObject.Transform.Position = Vector2D.Zero; | ||||
|         rigidBody.Velocity = GetRandomDirection() * Speed; | ||||
|  | ||||
|         SendBallData(); | ||||
|     } | ||||
|  | ||||
|     private Vector2D GetRandomDirection() | ||||
|     { | ||||
|         const float AllowedRadians = 45f * Syntriax.Engine.Core.Math.DegreeToRadian; | ||||
|         float rotation = (float)random.NextDouble() * 2f * AllowedRadians - AllowedRadians; | ||||
|         bool isBackwards = (random.Next() % 2) == 1; | ||||
|         return Vector2D.Right.Rotate(isBackwards ? rotation + Syntriax.Engine.Core.Math.PI : rotation); | ||||
|     } | ||||
|  | ||||
|     protected override void OnUpdate() | ||||
|     { | ||||
|         if (rigidBody.Velocity.MagnitudeSquared <= 0.01f) | ||||
|             return; | ||||
|  | ||||
|         Vector2D speedUp = rigidBody.Velocity.Normalized * Time.DeltaTimeFrame; | ||||
|         rigidBody.Velocity += speedUp * SpeedUpMultiplier; | ||||
|     } | ||||
|  | ||||
|     private void OnCollisionDetected(ICollider2D collider2D, CollisionDetectionInformation information) | ||||
|     { | ||||
|         if (Syntriax.Engine.Core.Math.Abs(information.Normal.Dot(Vector2D.Right)) > .25) | ||||
|             rigidBody.Velocity = information.Left.Transform.Position.FromTo(information.Right.Transform.Position).Normalized * rigidBody.Velocity.Magnitude; | ||||
|         else | ||||
|             rigidBody.Velocity = rigidBody.Velocity.Reflect(information.Normal); | ||||
|  | ||||
|         soundEffect.Play(); | ||||
|  | ||||
|         SendBallData(); | ||||
|     } | ||||
|  | ||||
|     private void SendBallData() | ||||
|     { | ||||
|         if (communicator is not INetworkServer server) | ||||
|             return; | ||||
|  | ||||
|         LiteNetLib.Utils.NetDataWriter dataWriter = communicator.GetMessageWriter(this); | ||||
|         dataWriter.Put(rigidBody.Transform.Position); | ||||
|         dataWriter.Put(rigidBody.Velocity); | ||||
|         server.Manager.SendToAll(dataWriter, LiteNetLib.DeliveryMethod.ReliableOrdered); | ||||
|     } | ||||
|  | ||||
|     protected override void OnMessageReceived(NetPacketReader reader, NetPeer peer) | ||||
|     { | ||||
|         rigidBody.Transform.Position = reader.GetVector2D(); | ||||
|         rigidBody.Velocity = reader.GetVector2D(); | ||||
|     } | ||||
|  | ||||
|     public BallBehaviour() { } | ||||
|     public BallBehaviour(Vector2D startDirection, float speed) | ||||
|     { | ||||
|         StartDirection = Vector2D.Normalize(startDirection); | ||||
|         Speed = speed; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										74
									
								
								Game/Behaviours/CameraController.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								Game/Behaviours/CameraController.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,74 @@ | ||||
| using Microsoft.Xna.Framework.Input; | ||||
|  | ||||
| using Syntriax.Engine.Core; | ||||
| using Syntriax.Engine.Input; | ||||
|  | ||||
| namespace Pong.Behaviours; | ||||
|  | ||||
| public class CameraController : BehaviourOverride | ||||
| { | ||||
|     private MonoGameCamera2DBehaviour cameraBehaviour = null!; | ||||
|     private IButtonInputs<Keys> buttonInputs = null!; | ||||
|  | ||||
|     private float defaultZoomLevel = 1f; | ||||
|  | ||||
|     protected override void OnFirstActiveFrame() | ||||
|     { | ||||
|         if (BehaviourController.TryGetBehaviour(out MonoGameCamera2DBehaviour? foundCameraBehaviour)) | ||||
|             cameraBehaviour = foundCameraBehaviour; | ||||
|  | ||||
|         cameraBehaviour ??= BehaviourController.AddBehaviour<MonoGameCamera2DBehaviour>(); | ||||
|  | ||||
|         if (BehaviourController.TryGetBehaviour(out IButtonInputs<Keys>? foundButtonInputs)) | ||||
|             buttonInputs = foundButtonInputs; | ||||
|  | ||||
|         buttonInputs ??= BehaviourController.AddBehaviour<KeyboardInputsBehaviour>(); | ||||
|         buttonInputs.RegisterOnPress(Keys.F, SwitchToFullScreen); | ||||
|         buttonInputs.RegisterOnPress(Keys.R, ResetCamera); | ||||
|     } | ||||
|  | ||||
|     protected override void OnUpdate() | ||||
|     { | ||||
|         if (buttonInputs.IsPressed(Keys.U)) | ||||
|             cameraBehaviour.Zoom += Time.Elapsed.Nanoseconds * 0.00025f; | ||||
|         if (buttonInputs.IsPressed(Keys.J)) | ||||
|             cameraBehaviour.Zoom -= Time.Elapsed.Nanoseconds * 0.00025f; | ||||
|  | ||||
|  | ||||
|         if (buttonInputs.IsPressed(Keys.NumPad8)) cameraBehaviour.BehaviourController.GameObject.Transform.Position += Vector2D.Up.Rotate(Transform.Rotation * Math.DegreeToRadian) * Time.DeltaTimeFrame; | ||||
|         if (buttonInputs.IsPressed(Keys.NumPad2)) cameraBehaviour.BehaviourController.GameObject.Transform.Position -= Vector2D.Up.Rotate(Transform.Rotation * Math.DegreeToRadian) * Time.DeltaTimeFrame; | ||||
|         if (buttonInputs.IsPressed(Keys.NumPad6)) cameraBehaviour.BehaviourController.GameObject.Transform.Position += Vector2D.Right.Rotate(Transform.Rotation * Math.DegreeToRadian) * Time.DeltaTimeFrame; | ||||
|         if (buttonInputs.IsPressed(Keys.NumPad4)) cameraBehaviour.BehaviourController.GameObject.Transform.Position -= Vector2D.Right.Rotate(Transform.Rotation * Math.DegreeToRadian) * Time.DeltaTimeFrame; | ||||
|  | ||||
|  | ||||
|         if (buttonInputs.IsPressed(Keys.Q)) | ||||
|             cameraBehaviour.BehaviourController.GameObject.Transform.Rotation += Time.Elapsed.Nanoseconds * 0.0025f; | ||||
|         if (buttonInputs.IsPressed(Keys.E)) | ||||
|             cameraBehaviour.BehaviourController.GameObject.Transform.Rotation -= Time.Elapsed.Nanoseconds * 0.0025f; | ||||
|     } | ||||
|  | ||||
|     private void SwitchToFullScreen(IButtonInputs<Keys> inputs, Keys keys) | ||||
|     { | ||||
|         if (cameraBehaviour.Graphics.IsFullScreen) | ||||
|             return; | ||||
|  | ||||
|         cameraBehaviour.Graphics.PreferMultiSampling = false; | ||||
|         cameraBehaviour.Graphics.PreferredBackBufferWidth = cameraBehaviour.Graphics.GraphicsDevice.Adapter.CurrentDisplayMode.Width; | ||||
|         cameraBehaviour.Graphics.PreferredBackBufferHeight = cameraBehaviour.Graphics.GraphicsDevice.Adapter.CurrentDisplayMode.Height; | ||||
|         cameraBehaviour.Graphics.IsFullScreen = true; | ||||
|         cameraBehaviour.Graphics.ApplyChanges(); | ||||
|  | ||||
|         float previousScreenSize = Math.Sqrt(Math.Sqr(cameraBehaviour.Viewport.Width) + Math.Sqr(cameraBehaviour.Viewport.Height)); | ||||
|         float currentScreenSize = Math.Sqrt(Math.Sqr(cameraBehaviour.Graphics.GraphicsDevice.Viewport.Width) + Math.Sqr(cameraBehaviour.Graphics.GraphicsDevice.Viewport.Height)); | ||||
|         defaultZoomLevel /= previousScreenSize / currentScreenSize; | ||||
|         cameraBehaviour.Zoom /= previousScreenSize / currentScreenSize; | ||||
|         cameraBehaviour.Viewport = cameraBehaviour.Graphics.GraphicsDevice.Viewport; | ||||
|     } | ||||
|  | ||||
|     private void ResetCamera(IButtonInputs<Keys> inputs, Keys keys) | ||||
|     { | ||||
|         cameraBehaviour.Zoom = defaultZoomLevel; | ||||
|         Transform.Position = Vector2D.Zero; | ||||
|         Transform.Rotation = 0f; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										29
									
								
								Game/Behaviours/CircleBehaviour.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								Game/Behaviours/CircleBehaviour.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,29 @@ | ||||
| using Microsoft.Xna.Framework; | ||||
|  | ||||
| using Apos.Shapes; | ||||
|  | ||||
| using Syntriax.Engine.Core.Abstract; | ||||
| using Syntriax.Engine.Physics2D.Primitives; | ||||
|  | ||||
| namespace Pong.Behaviours; | ||||
|  | ||||
| public class CircleBehaviour : Syntriax.Engine.Physics2D.Collider2DCircleBehaviour, IDisplayableShape | ||||
| { | ||||
|     public Color Color { get; set; } = Color.White; | ||||
|     public float Thickness { get; set; } = .5f; | ||||
|  | ||||
|     public void Draw(ShapeBatch shapeBatch) | ||||
|     { | ||||
|         if (!IsActive) | ||||
|             return; | ||||
|  | ||||
|         Recalculate(); | ||||
|  | ||||
|         shapeBatch.BorderCircle(CircleWorld.Center.ToDisplayVector2(), CircleWorld.Radius, Color); | ||||
|     } | ||||
|  | ||||
|     public CircleBehaviour(Circle circle) : base(circle) { } | ||||
|     public CircleBehaviour(Circle circle, float thickness) : base(circle) { Thickness = thickness; } | ||||
|     public CircleBehaviour(Circle circle, Color color) : base(circle) { Color = color; } | ||||
|     public CircleBehaviour(Circle circle, Color color, float thickness) : base(circle) { Thickness = thickness; Color = color; } | ||||
| } | ||||
							
								
								
									
										106
									
								
								Game/Behaviours/KeyboardInputsBehaviour.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										106
									
								
								Game/Behaviours/KeyboardInputsBehaviour.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,106 @@ | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using Microsoft.Xna.Framework.Input; | ||||
|  | ||||
| using Syntriax.Engine.Core; | ||||
| using Syntriax.Engine.Input; | ||||
|  | ||||
| namespace Pong.Behaviours; | ||||
|  | ||||
| public class KeyboardInputsBehaviour : BehaviourOverride, IButtonInputs<Keys> | ||||
| { | ||||
|     private readonly Dictionary<Keys, Action<IButtonInputs<Keys>, Keys>?> OnPressed = new(256); | ||||
|     private readonly Dictionary<Keys, Action<IButtonInputs<Keys>, Keys>?> OnReleased = new(256); | ||||
|  | ||||
|     private int cachePressedCurrentlyCount = 0; | ||||
|     private readonly Keys[] cachePressedCurrently = new Keys[256]; | ||||
|  | ||||
|     private int cachePressedPreviouslyCount = 0; | ||||
|     private readonly Keys[] cachePressedPreviously = new Keys[256]; | ||||
|  | ||||
|     public void RegisterOnPress(Keys key, Action<IButtonInputs<Keys>, Keys> callback) | ||||
|     { | ||||
|         if (OnPressed.TryGetValue(key, out var action)) | ||||
|         { | ||||
|             action += callback; | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         OnPressed.Add(key, callback); | ||||
|     } | ||||
|  | ||||
|     public void UnregisterOnPress(Keys key, Action<IButtonInputs<Keys>, Keys> callback) | ||||
|     { | ||||
|         if (OnPressed.TryGetValue(key, out var action)) | ||||
|             action -= callback; | ||||
|     } | ||||
|  | ||||
|     public void RegisterOnRelease(Keys key, Action<IButtonInputs<Keys>, Keys> callback) | ||||
|     { | ||||
|         if (OnReleased.TryGetValue(key, out var action)) | ||||
|         { | ||||
|             action += callback; | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         OnReleased.Add(key, callback); | ||||
|     } | ||||
|  | ||||
|     public void UnregisterOnRelease(Keys key, Action<IButtonInputs<Keys>, Keys> callback) | ||||
|     { | ||||
|         if (OnReleased.TryGetValue(key, out var action)) | ||||
|             action -= callback; | ||||
|     } | ||||
|  | ||||
|     protected override void OnUpdate() | ||||
|     { | ||||
|         KeyboardState keyboardState = Keyboard.GetState(); | ||||
|         keyboardState.GetPressedKeys(cachePressedCurrently); | ||||
|         cachePressedCurrentlyCount = keyboardState.GetPressedKeyCount(); | ||||
|  | ||||
|         for (int i = 0; i < cachePressedCurrentlyCount; i++) | ||||
|         { | ||||
|             Keys currentlyPressedKey = cachePressedCurrently[i]; | ||||
|  | ||||
|             if (!OnPressed.TryGetValue(currentlyPressedKey, out var action)) | ||||
|                 continue; | ||||
|  | ||||
|             if (WasPressed(currentlyPressedKey)) | ||||
|                 continue; | ||||
|  | ||||
|             action?.Invoke(this, currentlyPressedKey); | ||||
|         } | ||||
|  | ||||
|         for (int i = 0; i < cachePressedPreviouslyCount; i++) | ||||
|         { | ||||
|             Keys previouslyPressedKey = cachePressedPreviously[i]; | ||||
|  | ||||
|             if (!OnReleased.TryGetValue(previouslyPressedKey, out var action)) | ||||
|                 continue; | ||||
|  | ||||
|             if (IsPressed(previouslyPressedKey)) | ||||
|                 continue; | ||||
|  | ||||
|             action?.Invoke(this, previouslyPressedKey); | ||||
|         } | ||||
|  | ||||
|         Array.Copy(cachePressedCurrently, cachePressedPreviously, cachePressedCurrentlyCount); | ||||
|         cachePressedPreviouslyCount = cachePressedCurrentlyCount; | ||||
|     } | ||||
|  | ||||
|     public bool IsPressed(Keys key) | ||||
|     { | ||||
|         for (int i = 0; i < cachePressedCurrentlyCount; i++) | ||||
|             if (cachePressedCurrently[i] == key) | ||||
|                 return true; | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     public bool WasPressed(Keys key) | ||||
|     { | ||||
|         for (int i = 0; i < cachePressedPreviouslyCount; i++) | ||||
|             if (cachePressedPreviously[i] == key) | ||||
|                 return true; | ||||
|         return false; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										102
									
								
								Game/Behaviours/MonoGameCamera2DBehaviour.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										102
									
								
								Game/Behaviours/MonoGameCamera2DBehaviour.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,102 @@ | ||||
| using Microsoft.Xna.Framework; | ||||
| using Microsoft.Xna.Framework.Graphics; | ||||
|  | ||||
| using Syntriax.Engine.Core; | ||||
| using Syntriax.Engine.Core.Abstract; | ||||
|  | ||||
| namespace Pong.Behaviours; | ||||
|  | ||||
| public class MonoGameCamera2DBehaviour(GraphicsDeviceManager Graphics) : BehaviourOverride, ICamera2D | ||||
| { | ||||
|     public System.Action<MonoGameCamera2DBehaviour>? OnMatrixTransformChanged { get; set; } = null; | ||||
|     public System.Action<MonoGameCamera2DBehaviour>? OnViewportChanged { get; set; } = null; | ||||
|     public System.Action<MonoGameCamera2DBehaviour>? OnZoomChanged { get; set; } = null; | ||||
|  | ||||
|     private Matrix _matrixTransform = Matrix.Identity; | ||||
|  | ||||
|     private Viewport _viewport = default; | ||||
|     private float _zoom = 1f; | ||||
|  | ||||
|     public GraphicsDeviceManager Graphics { get; } = Graphics; | ||||
|  | ||||
|     public Matrix MatrixTransform | ||||
|     { | ||||
|         get => _matrixTransform; | ||||
|         set | ||||
|         { | ||||
|             if (_matrixTransform == value) | ||||
|                 return; | ||||
|  | ||||
|             _matrixTransform = value; | ||||
|             OnMatrixTransformChanged?.Invoke(this); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public Vector2D Position | ||||
|     { | ||||
|         get => Transform.Position; | ||||
|         set => Transform.Position = value; | ||||
|     } | ||||
|  | ||||
|     public Viewport Viewport | ||||
|     { | ||||
|         get => _viewport; | ||||
|         set | ||||
|         { | ||||
|             if (_viewport.Equals(value)) | ||||
|                 return; | ||||
|  | ||||
|             _viewport = value; | ||||
|             OnViewportChanged?.Invoke(this); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public float Zoom | ||||
|     { | ||||
|         get => _zoom; | ||||
|         set | ||||
|         { | ||||
|             float newValue = Math.Max(0.1f, value); | ||||
|  | ||||
|             if (_zoom == newValue) | ||||
|                 return; | ||||
|  | ||||
|             _zoom = newValue; | ||||
|             OnZoomChanged?.Invoke(this); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public float Rotation | ||||
|     { | ||||
|         get => Transform.Rotation; | ||||
|         set => Transform.Rotation = value; | ||||
|     } | ||||
|  | ||||
|     System.Action<IAssignableTransform>? IAssignableTransform.OnTransformAssigned { get => GameObject.OnTransformAssigned; set => GameObject.OnTransformAssigned = value; } | ||||
|     ITransform IAssignableTransform.Transform => GameObject.Transform; | ||||
|     bool IAssignableTransform.Assign(ITransform transform) => GameObject.Assign(transform); | ||||
|  | ||||
|     // TODO This causes delay since OnPreDraw calls assuming this is called in in Update  | ||||
|     public Vector2D ScreenToWorldPosition(Vector2D screenPosition) | ||||
|     { | ||||
|         Vector2D worldPosition = Vector2.Transform(screenPosition.ToVector2(), Matrix.Invert(MatrixTransform)).ToVector2D(); | ||||
|         return worldPosition.Scale(EngineConverter.screenScale); | ||||
|     } | ||||
|     public Vector2D WorldToScreenPosition(Vector2D worldPosition) | ||||
|     { | ||||
|         Vector2D screenPosition = Vector2.Transform(worldPosition.ToVector2(), MatrixTransform).ToVector2D(); | ||||
|         return screenPosition.Scale(EngineConverter.screenScale); | ||||
|     } | ||||
|  | ||||
|     protected override void OnFirstActiveFrame() | ||||
|         => Viewport = Graphics.GraphicsDevice.Viewport; | ||||
|  | ||||
|     protected override void OnPreDraw() | ||||
|     { | ||||
|         MatrixTransform = | ||||
|             Matrix.CreateTranslation(new Vector3(-Position.X, Position.Y, 0f)) * | ||||
|             Matrix.CreateRotationZ(Rotation * Math.DegreeToRadian) * | ||||
|             Matrix.CreateScale(Zoom) * | ||||
|             Matrix.CreateTranslation(new Vector3(_viewport.Width * .5f, _viewport.Height * .5f, 0f)); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										53
									
								
								Game/Behaviours/MovementBallBehaviour.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								Game/Behaviours/MovementBallBehaviour.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,53 @@ | ||||
| using System; | ||||
|  | ||||
| using Syntriax.Engine.Core; | ||||
| using Syntriax.Engine.Physics2D; | ||||
| using Syntriax.Engine.Physics2D.Abstract; | ||||
|  | ||||
| namespace Pong.Behaviours; | ||||
|  | ||||
| public class MovementBallBehaviour : BehaviourOverride | ||||
| { | ||||
|     public Vector2D StartDirection { get; private set; } = Vector2D.Zero; | ||||
|     public float Speed { get; set; } = 500f; | ||||
|     public float SpeedUpMultiplier { get; set; } = .0125f; | ||||
|  | ||||
|     private IRigidBody2D rigidBody = null!; | ||||
|  | ||||
|     protected override void OnFirstActiveFrame() | ||||
|     { | ||||
|         if (!BehaviourController.TryGetBehaviour(out IRigidBody2D? foundRigidBody)) | ||||
|             throw new Exception($"{nameof(IRigidBody2D)} is missing on {GameObject.Name}."); | ||||
|         if (!BehaviourController.TryGetBehaviour(out ICollider2D? foundCollider)) | ||||
|             throw new Exception($"{nameof(ICollider2D)} is missing on {GameObject.Name}."); | ||||
|  | ||||
|         foundRigidBody.Velocity = StartDirection * Speed; | ||||
|         foundCollider.OnCollisionDetected += OnCollisionDetected; | ||||
|  | ||||
|         rigidBody = foundRigidBody; | ||||
|     } | ||||
|  | ||||
|     protected override void OnUpdate() | ||||
|     { | ||||
|         if (rigidBody.Velocity.MagnitudeSquared <= 0.01f) | ||||
|             return; | ||||
|  | ||||
|         Vector2D speedUp = rigidBody.Velocity.Normalized * Time.DeltaTimeFrame; | ||||
|         rigidBody.Velocity += speedUp * SpeedUpMultiplier; | ||||
|     } | ||||
|  | ||||
|     private void OnCollisionDetected(ICollider2D collider2D, CollisionDetectionInformation information) | ||||
|     { | ||||
|         if (Syntriax.Engine.Core.Math.Abs(information.Normal.Dot(Vector2D.Right)) > .25) | ||||
|             rigidBody.Velocity = information.Left.Transform.Position.FromTo(information.Right.Transform.Position).Normalized * rigidBody.Velocity.Magnitude; | ||||
|         else | ||||
|             rigidBody.Velocity = rigidBody.Velocity.Reflect(information.Normal); | ||||
|     } | ||||
|  | ||||
|     public MovementBallBehaviour() { } | ||||
|     public MovementBallBehaviour(Vector2D startDirection, float speed) | ||||
|     { | ||||
|         StartDirection = Vector2D.Normalize(startDirection); | ||||
|         Speed = speed; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										154
									
								
								Game/Behaviours/NetworkedKeyboardInputs.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										154
									
								
								Game/Behaviours/NetworkedKeyboardInputs.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,154 @@ | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using LiteNetLib; | ||||
| using Microsoft.Xna.Framework.Input; | ||||
| using Syntriax.Engine.Input; | ||||
| using Syntriax.Engine.Network; | ||||
|  | ||||
| namespace Pong.Behaviours; | ||||
|  | ||||
| public class NetworkedKeyboardInputs : NetworkBehaviour, IButtonInputs<Keys> | ||||
| { | ||||
|     private readonly Dictionary<Keys, Action<IButtonInputs<Keys>, Keys>?> OnPressed = new(256); | ||||
|     private readonly Dictionary<Keys, Action<IButtonInputs<Keys>, Keys>?> OnReleased = new(256); | ||||
|  | ||||
|     private int cachePressedCurrentlyCount = 0; | ||||
|     private readonly Keys[] cachePressedCurrently = new Keys[256]; | ||||
|  | ||||
|     private int cachePressedPreviouslyCount = 0; | ||||
|     private readonly Keys[] cachePressedPreviously = new Keys[256]; | ||||
|  | ||||
|     public void RegisterOnPress(Keys key, Action<IButtonInputs<Keys>, Keys> callback) | ||||
|     { | ||||
|         if (OnPressed.TryGetValue(key, out var action)) | ||||
|         { | ||||
|             action += callback; | ||||
|             OnPressed.Remove(key); | ||||
|             OnPressed.Add(key, action); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         OnPressed.Add(key, callback); | ||||
|     } | ||||
|  | ||||
|     public void UnregisterOnPress(Keys key, Action<IButtonInputs<Keys>, Keys> callback) | ||||
|     { | ||||
|         if (OnPressed.TryGetValue(key, out var action)) | ||||
|             action -= callback; | ||||
|     } | ||||
|  | ||||
|     public void RegisterOnRelease(Keys key, Action<IButtonInputs<Keys>, Keys> callback) | ||||
|     { | ||||
|         if (OnReleased.TryGetValue(key, out var action)) | ||||
|         { | ||||
|             action += callback; | ||||
|             OnReleased.Remove(key); | ||||
|             OnReleased.Add(key, action); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         OnReleased.Add(key, callback); | ||||
|     } | ||||
|  | ||||
|     public void UnregisterOnRelease(Keys key, Action<IButtonInputs<Keys>, Keys> callback) | ||||
|     { | ||||
|         if (OnReleased.TryGetValue(key, out var action)) | ||||
|             action -= callback; | ||||
|     } | ||||
|  | ||||
|     protected override void OnUpdate() | ||||
|     { | ||||
|         if (!IsServer && !LocalAssigned) | ||||
|             return; | ||||
|  | ||||
|         KeyboardState keyboardState = Keyboard.GetState(); | ||||
|         keyboardState.GetPressedKeys(cachePressedCurrently); | ||||
|         cachePressedCurrentlyCount = keyboardState.GetPressedKeyCount(); | ||||
|  | ||||
|         for (int i = 0; i < cachePressedCurrentlyCount; i++) | ||||
|         { | ||||
|             Keys currentlyPressedKey = cachePressedCurrently[i]; | ||||
|  | ||||
|             if (!OnPressed.TryGetValue(currentlyPressedKey, out var action)) | ||||
|                 continue; | ||||
|  | ||||
|             if (WasPressed(currentlyPressedKey)) | ||||
|                 continue; | ||||
|  | ||||
|             action?.Invoke(this, currentlyPressedKey); | ||||
|         } | ||||
|  | ||||
|         for (int i = 0; i < cachePressedPreviouslyCount; i++) | ||||
|         { | ||||
|             Keys previouslyPressedKey = cachePressedPreviously[i]; | ||||
|  | ||||
|             if (!OnReleased.TryGetValue(previouslyPressedKey, out var action)) | ||||
|                 continue; | ||||
|  | ||||
|             if (IsPressed(previouslyPressedKey)) | ||||
|                 continue; | ||||
|  | ||||
|             action?.Invoke(this, previouslyPressedKey); | ||||
|         } | ||||
|  | ||||
|         Array.Copy(cachePressedCurrently, cachePressedPreviously, cachePressedCurrentlyCount); | ||||
|         cachePressedPreviouslyCount = cachePressedCurrentlyCount; | ||||
|     } | ||||
|  | ||||
|     public bool IsPressed(Keys key) | ||||
|     { | ||||
|         for (int i = 0; i < cachePressedCurrentlyCount; i++) | ||||
|             if (cachePressedCurrently[i] == key) | ||||
|                 return true; | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     public bool WasPressed(Keys key) | ||||
|     { | ||||
|         for (int i = 0; i < cachePressedPreviouslyCount; i++) | ||||
|             if (cachePressedPreviously[i] == key) | ||||
|                 return true; | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     protected override void OnInitialize() | ||||
|     { | ||||
|         base.OnInitialize(); | ||||
|         foreach (Keys key in Enum.GetValues(typeof(Keys))) | ||||
|         { | ||||
|             RegisterOnPress(key, (keys, keyVal) => | ||||
|             { | ||||
|                 if (!LocalAssigned && !IsServer) | ||||
|                     return; | ||||
|  | ||||
|                 var netDataWriter = NetworkCommunicator.GetMessageWriter(this); | ||||
|                 netDataWriter.Put(true); | ||||
|                 netDataWriter.Put((int)key); | ||||
|                 NetworkCommunicator.Manager.SendToAll(netDataWriter, DeliveryMethod.ReliableOrdered); | ||||
|             }); | ||||
|             RegisterOnRelease(key, (keys, keyVal) => | ||||
|             { | ||||
|                 if (!LocalAssigned && !IsServer) | ||||
|                     return; | ||||
|  | ||||
|                 var netDataWriter = NetworkCommunicator.GetMessageWriter(this); | ||||
|                 netDataWriter.Put(false); | ||||
|                 netDataWriter.Put((int)key); | ||||
|                 NetworkCommunicator.Manager.SendToAll(netDataWriter, DeliveryMethod.ReliableOrdered); | ||||
|             }); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     protected override void OnMessageReceived(NetPacketReader reader, NetPeer peer) | ||||
|     { | ||||
|         bool isPressed = reader.GetBool(); | ||||
|         Keys key = (Keys)reader.GetInt(); | ||||
|  | ||||
|         if (isPressed) | ||||
|             if (OnPressed.TryGetValue(key, out var action)) | ||||
|                 action?.Invoke(this, key); | ||||
|         if (!isPressed) | ||||
|             if (OnReleased.TryGetValue(key, out var action)) | ||||
|                 action?.Invoke(this, key); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										101
									
								
								Game/Behaviours/PaddleBehaviour.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								Game/Behaviours/PaddleBehaviour.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,101 @@ | ||||
| using System; | ||||
|  | ||||
| using Microsoft.Xna.Framework.Input; | ||||
|  | ||||
| using LiteNetLib; | ||||
| using LiteNetLib.Utils; | ||||
|  | ||||
| using Syntriax.Engine.Core; | ||||
| using Syntriax.Engine.Input; | ||||
| using Syntriax.Engine.Network; | ||||
| using Syntriax.Engine.Network.Abstract; | ||||
|  | ||||
| namespace Pong.Behaviours; | ||||
|  | ||||
| public class PaddleBehaviour(Keys Up, Keys Down, float High, float Low, float Speed) : BehaviourOverride | ||||
| { | ||||
|     private Keys Up { get; } = Up; | ||||
|     private Keys Down { get; } = Down; | ||||
|     public float High { get; } = High; | ||||
|     public float Low { get; } = Low; | ||||
|     public float Speed { get; set; } = Speed; | ||||
|  | ||||
|     private bool isUpPressed = false; | ||||
|     private bool isDownPressed = false; | ||||
|  | ||||
|     private IButtonInputs<Keys> inputs = null!; | ||||
|     private INetworkCommunicator communicator = null!; | ||||
|  | ||||
|     protected override void OnUpdate() | ||||
|     { | ||||
|         if (isUpPressed && isDownPressed) | ||||
|             return; | ||||
|  | ||||
|         if (isUpPressed) | ||||
|             MovePaddle(Vector2D.Up * (float)Time.Elapsed.TotalSeconds * Speed); | ||||
|         else if (isDownPressed) | ||||
|             MovePaddle(-Vector2D.Up * (float)Time.Elapsed.TotalSeconds * Speed); | ||||
|     } | ||||
|  | ||||
|     private void MovePaddle(Vector2D vectorToAdd) | ||||
|     { | ||||
|         GameObject.Transform.Position += vectorToAdd; | ||||
|         GameObject.Transform.Position = new Vector2D(GameObject.Transform.Position.X, MathF.Max(MathF.Min(GameObject.Transform.Position.Y, High), Low)); | ||||
|     } | ||||
|  | ||||
|     protected override void OnFirstActiveFrame() | ||||
|     { | ||||
|         BehaviourController.TryGetBehaviour<IButtonInputs<Keys>>(out var behaviourResult); | ||||
|         inputs = behaviourResult ?? throw new Exception($"{nameof(IButtonInputs<Keys>)} is missing on {GameObject.Name}."); | ||||
|  | ||||
|         if (!GameObject.GameManager.TryFindBehaviour(out INetworkCommunicator? foundCommunicator)) | ||||
|             throw new Exception($"{nameof(INetworkCommunicator)} is missing on GameManager."); | ||||
|  | ||||
|         inputs.RegisterOnPress(Up, OnUpPressed); | ||||
|         inputs.RegisterOnRelease(Up, OnUpReleased); | ||||
|  | ||||
|         inputs.RegisterOnPress(Down, OnDownPressed); | ||||
|         inputs.RegisterOnRelease(Down, OnDownReleased); | ||||
|  | ||||
|         communicator = foundCommunicator; | ||||
|         communicator.RegisterEntityListener(this, OnDataReceived); | ||||
|     } | ||||
|  | ||||
|     protected override void OnFinalize() | ||||
|     { | ||||
|         inputs.UnregisterOnPress(Up, OnUpPressed); | ||||
|         inputs.UnregisterOnRelease(Up, OnUpReleased); | ||||
|  | ||||
|         inputs.UnregisterOnPress(Down, OnDownPressed); | ||||
|         inputs.UnregisterOnRelease(Down, OnDownReleased); | ||||
|     } | ||||
|  | ||||
|     private void UpdateNetwork() | ||||
|     { | ||||
|         NetDataWriter netDataWriter = communicator.GetEntityWriter(this); | ||||
|         netDataWriter.Put(isUpPressed); | ||||
|         netDataWriter.Put(isDownPressed); | ||||
|         netDataWriter.Put(Transform.Position); | ||||
|         communicator.Manager.SendToAll(netDataWriter, DeliveryMethod.ReliableOrdered); | ||||
|     } | ||||
|  | ||||
|     private void OnDataReceived(NetPacketReader reader, NetPeer peer) | ||||
|     { | ||||
|         if (communicator is INetworkServer server) | ||||
|         { | ||||
|             reader.Get(out isUpPressed); | ||||
|             reader.Get(out isDownPressed); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             reader.Get(out isUpPressed); | ||||
|             reader.Get(out isDownPressed); | ||||
|             Transform.Position = reader.GetVector2D(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private void OnUpPressed(IButtonInputs<Keys> inputs, Keys keys) { isUpPressed = true; UpdateNetwork(); } | ||||
|     private void OnUpReleased(IButtonInputs<Keys> inputs, Keys keys) { isUpPressed = false; UpdateNetwork(); } | ||||
|     private void OnDownPressed(IButtonInputs<Keys> inputs, Keys keys) { isDownPressed = true; UpdateNetwork(); } | ||||
|     private void OnDownReleased(IButtonInputs<Keys> inputs, Keys keys) { isDownPressed = false; UpdateNetwork(); } | ||||
| } | ||||
							
								
								
									
										104
									
								
								Game/Behaviours/PongManagerBehaviour.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										104
									
								
								Game/Behaviours/PongManagerBehaviour.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,104 @@ | ||||
| using System; | ||||
|  | ||||
| using Microsoft.Xna.Framework.Input; | ||||
|  | ||||
| using LiteNetLib; | ||||
|  | ||||
| using Syntriax.Engine.Core; | ||||
| using Syntriax.Engine.Network; | ||||
| using Syntriax.Engine.Network.Abstract; | ||||
|  | ||||
| namespace Pong.Behaviours; | ||||
|  | ||||
| public class PongManagerBehaviour : NetworkBehaviour | ||||
| { | ||||
|     public Action<PongManagerBehaviour>? OnReset { get; set; } = null; | ||||
|     public Action<PongManagerBehaviour>? OnFinished { get; set; } = null; | ||||
|     public Action<PongManagerBehaviour>? OnScoresUpdated { get; set; } = null; | ||||
|     public Action<PongManagerBehaviour>? OnScored { get; set; } = null; | ||||
|  | ||||
|     private INetworkCommunicator communicator = null!; | ||||
|  | ||||
|     public int ScoreLeft { get; private set; } = 0; | ||||
|     public int ScoreRight { get; private set; } = 0; | ||||
|     public int ScoreSum => ScoreLeft + ScoreRight; | ||||
|  | ||||
|     public int WinScore { get; } = 5; | ||||
|  | ||||
|     public PongManagerBehaviour() => WinScore = 5; | ||||
|     public PongManagerBehaviour(int winScore) => WinScore = winScore; | ||||
|  | ||||
|     protected override void OnFirstActiveFrame() | ||||
|     { | ||||
|         KeyboardInputsBehaviour? buttonInputs = null!; | ||||
|  | ||||
|         if (!BehaviourController.TryGetBehaviour(out buttonInputs)) | ||||
|             buttonInputs = BehaviourController.AddBehaviour<KeyboardInputsBehaviour>(); | ||||
|  | ||||
|         if (!GameObject.GameManager.TryFindBehaviour(out INetworkCommunicator? foundCommunicator)) | ||||
|             throw new Exception($"{nameof(INetworkCommunicator)} is missing on GameManager."); | ||||
|  | ||||
|         buttonInputs.RegisterOnRelease(Keys.Space, (_, _1) => Reset()); | ||||
|  | ||||
|         communicator = foundCommunicator; | ||||
|     } | ||||
|  | ||||
|     public void ScoreToLeft() | ||||
|     { | ||||
|         ScoreLeft++; | ||||
|         OnScoresUpdated?.Invoke(this); | ||||
|         OnScored?.Invoke(this); | ||||
|  | ||||
|         SendData(); | ||||
|  | ||||
|         CheckFinish(); | ||||
|     } | ||||
|  | ||||
|     public void ScoreToRight() | ||||
|     { | ||||
|         ScoreRight++; | ||||
|         OnScoresUpdated?.Invoke(this); | ||||
|         OnScored?.Invoke(this); | ||||
|  | ||||
|         SendData(); | ||||
|  | ||||
|         CheckFinish(); | ||||
|     } | ||||
|  | ||||
|     public void Reset() | ||||
|     { | ||||
|         ScoreLeft = ScoreRight = 0; | ||||
|         OnScoresUpdated?.Invoke(this); | ||||
|         OnReset?.Invoke(this); | ||||
|  | ||||
|         SendData(); | ||||
|     } | ||||
|  | ||||
|     private void CheckFinish() | ||||
|     { | ||||
|         int halfwayScore = (int)(WinScore * .5f); | ||||
|  | ||||
|         if (ScoreLeft > halfwayScore || ScoreRight > halfwayScore) | ||||
|             OnFinished?.Invoke(this); | ||||
|     } | ||||
|  | ||||
|     private void SendData() | ||||
|     { | ||||
|         if (communicator is not INetworkServer server) | ||||
|             return; | ||||
|  | ||||
|         LiteNetLib.Utils.NetDataWriter dataWriter = communicator.GetMessageWriter(this); | ||||
|         dataWriter.Put(ScoreLeft); | ||||
|         dataWriter.Put(ScoreRight); | ||||
|         server.Manager.SendToAll(dataWriter, LiteNetLib.DeliveryMethod.ReliableOrdered); | ||||
|     } | ||||
|  | ||||
|     protected override void OnMessageReceived(NetPacketReader reader, NetPeer peer) | ||||
|     { | ||||
|         ScoreLeft = reader.GetInt(); | ||||
|         ScoreRight = reader.GetInt(); | ||||
|         OnScoresUpdated?.Invoke(this); | ||||
|  | ||||
|         CheckFinish(); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										48
									
								
								Game/Behaviours/ShapeAABBBehaviour.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								Game/Behaviours/ShapeAABBBehaviour.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,48 @@ | ||||
| using Microsoft.Xna.Framework; | ||||
|  | ||||
| using Apos.Shapes; | ||||
|  | ||||
| using Syntriax.Engine.Core; | ||||
| using Syntriax.Engine.Core.Abstract; | ||||
| using Syntriax.Engine.Input; | ||||
| using Syntriax.Engine.Physics2D.Abstract; | ||||
| using Syntriax.Engine.Physics2D.Primitives; | ||||
|  | ||||
| namespace Pong.Behaviours; | ||||
|  | ||||
| public class ShapeAABBBehaviour : BehaviourOverride, IDisplayableShape | ||||
| { | ||||
|     private IShapeCollider2D? shapeCollider = null; | ||||
|  | ||||
|     public Color Color { get; set; } = Color.White; | ||||
|     public float Thickness { get; set; } = .5f; | ||||
|     public bool display = true; | ||||
|  | ||||
|     protected override void OnFirstActiveFrame() | ||||
|     { | ||||
|         BehaviourController.TryGetBehaviour(out shapeCollider); | ||||
|  | ||||
|         if (BehaviourController.TryGetBehaviour(out IButtonInputs<Microsoft.Xna.Framework.Input.Keys>? keys)) | ||||
|             keys.RegisterOnPress(Microsoft.Xna.Framework.Input.Keys.D, (_1, _2) => display = !display); | ||||
|     } | ||||
|  | ||||
|     public void Draw(ShapeBatch shapeBatch) | ||||
|     { | ||||
|         if (!display) | ||||
|             return; | ||||
|  | ||||
|         if (shapeCollider is null) | ||||
|             return; | ||||
|  | ||||
|         AABB aabb = AABB.FromVectors(shapeCollider.ShapeWorld); | ||||
|  | ||||
|         shapeBatch.BorderCircle(aabb.Center.ToDisplayVector2(), 7.5f, Color.Beige); | ||||
|  | ||||
|         shapeBatch.DrawRectangle(aabb.Center.ApplyDisplayScale().Subtract(aabb.SizeHalf).ToVector2(), aabb.Size.ToVector2(), Color.Transparent, Color.Blue); | ||||
|     } | ||||
|  | ||||
|     public ShapeAABBBehaviour() { } | ||||
|     public ShapeAABBBehaviour(float Thickness) { this.Thickness = Thickness; } | ||||
|     public ShapeAABBBehaviour(Color color) { Color = color; } | ||||
|     public ShapeAABBBehaviour(Color color, float Thickness) { this.Thickness = Thickness; Color = color; } | ||||
| } | ||||
							
								
								
									
										33
									
								
								Game/Behaviours/ShapeBehaviour.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								Game/Behaviours/ShapeBehaviour.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,33 @@ | ||||
| using Microsoft.Xna.Framework; | ||||
|  | ||||
| using Apos.Shapes; | ||||
|  | ||||
| using Syntriax.Engine.Core.Abstract; | ||||
| using Syntriax.Engine.Physics2D.Primitives; | ||||
|  | ||||
| namespace Pong.Behaviours; | ||||
|  | ||||
| public class ShapeBehaviour : Syntriax.Engine.Physics2D.Collider2DShapeBehaviour, IDisplayableShape | ||||
| { | ||||
|     public Color Color { get; set; } = Color.White; | ||||
|     public float Thickness { get; set; } = .5f; | ||||
|  | ||||
|     public void Draw(ShapeBatch shapeBatch) | ||||
|     { | ||||
|         if (!IsActive) | ||||
|             return; | ||||
|  | ||||
|         Recalculate(); | ||||
|  | ||||
|         int count = ShapeWorld.Vertices.Count; | ||||
|  | ||||
|         for (int i = 0; i < count - 1; i++) | ||||
|             shapeBatch.DrawLine(ShapeWorld[i].ToDisplayVector2(), ShapeWorld[i + 1].ToDisplayVector2(), Thickness, Color, Color); | ||||
|         shapeBatch.DrawLine(ShapeWorld[0].ToDisplayVector2(), ShapeWorld[^1].ToDisplayVector2(), Thickness, Color, Color); | ||||
|     } | ||||
|  | ||||
|     public ShapeBehaviour(Shape shape) : base(shape) { } | ||||
|     public ShapeBehaviour(Shape shape, float thickness) : base(shape) { Thickness = thickness; } | ||||
|     public ShapeBehaviour(Shape shape, Color color) : base(shape) { Color = color; } | ||||
|     public ShapeBehaviour(Shape shape, Color color, float thickness) : base(shape) { Thickness = thickness; Color = color; } | ||||
| } | ||||
							
								
								
									
										25
									
								
								Game/Behaviours/TextBehaviour.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								Game/Behaviours/TextBehaviour.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | ||||
| using Microsoft.Xna.Framework; | ||||
| using Microsoft.Xna.Framework.Graphics; | ||||
|  | ||||
| using Syntriax.Engine.Core; | ||||
| using Syntriax.Engine.Core.Abstract; | ||||
|  | ||||
| namespace Pong.Behaviours; | ||||
|  | ||||
| public class TextBehaviour : BehaviourOverride, IDisplayableSprite | ||||
| { | ||||
|     public SpriteFont? Font { get; set; } = null; | ||||
|     public int Size { get; set; } = 16; | ||||
|     public string Text { get; set; } = string.Empty; | ||||
|  | ||||
|     public void Draw(SpriteBatch spriteBatch) | ||||
|     { | ||||
|         if (!IsActive || Font is null) | ||||
|             return; | ||||
|  | ||||
|         spriteBatch.DrawString(Font, Text, Transform.Position.ToDisplayVector2(), Color.White, Transform.Rotation, Vector2.One * .5f, Transform.Scale.Magnitude, SpriteEffects.None, 0f); | ||||
|     } | ||||
|  | ||||
|     public TextBehaviour() { } | ||||
|     public TextBehaviour(SpriteFont font) => Font = font; | ||||
| } | ||||
							
								
								
									
										32
									
								
								Game/Behaviours/TextScoreBehaviour.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								Game/Behaviours/TextScoreBehaviour.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,32 @@ | ||||
| using Microsoft.Xna.Framework.Graphics; | ||||
| using Syntriax.Engine.Core; | ||||
|  | ||||
| namespace Pong.Behaviours; | ||||
|  | ||||
| public class TextScoreBehaviour : TextBehaviour | ||||
| { | ||||
|     public bool IsLeft { get; } | ||||
|  | ||||
|     private PongManagerBehaviour? pongManager = null; | ||||
|  | ||||
|     protected override void OnFirstActiveFrame() | ||||
|     { | ||||
|         if (!GameObject.GameManager.TryFindBehaviour(out pongManager)) | ||||
|             return; | ||||
|  | ||||
|         pongManager.OnScoresUpdated += UpdateScores; | ||||
|  | ||||
|         UpdateScores(pongManager); | ||||
|     } | ||||
|  | ||||
|     private void UpdateScores(PongManagerBehaviour pongManager) | ||||
|     { | ||||
|         if (IsLeft) | ||||
|             Text = pongManager.ScoreLeft.ToString(); | ||||
|         else | ||||
|             Text = pongManager.ScoreRight.ToString(); | ||||
|     } | ||||
|  | ||||
|     public TextScoreBehaviour(bool IsLeft) => this.IsLeft = IsLeft; | ||||
|     public TextScoreBehaviour(bool IsLeft, SpriteFont font) : base(font) => this.IsLeft = IsLeft; | ||||
| } | ||||
							
								
								
									
										19
									
								
								Game/Behaviours/WallScoreBehaviour.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								Game/Behaviours/WallScoreBehaviour.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | ||||
| using System; | ||||
|  | ||||
| using Syntriax.Engine.Core; | ||||
| using Syntriax.Engine.Physics2D.Abstract; | ||||
|  | ||||
| namespace Pong.Behaviours; | ||||
|  | ||||
| public class WallScoreBehaviour(Action OnCollision) : BehaviourOverride | ||||
| { | ||||
|     private Action OnCollision { get; } = OnCollision; | ||||
|  | ||||
|     protected override void OnFirstActiveFrame() | ||||
|     { | ||||
|         if (!BehaviourController.TryGetBehaviour(out ICollider2D? collider2D)) | ||||
|             return; | ||||
|  | ||||
|         collider2D.OnCollisionDetected += (_, _1) => OnCollision?.Invoke(); | ||||
|     } | ||||
| } | ||||
| @@ -13,35 +13,11 @@ | ||||
| 
 | ||||
| #---------------------------------- Content ---------------------------------# | ||||
| 
 | ||||
| #begin Audio/Bounce.wav | ||||
| #begin Hit.wav | ||||
| /importer:WavImporter | ||||
| /processor:SoundEffectProcessor | ||||
| /processorParam:Quality=Best | ||||
| /build:Audio/Bounce.wav | ||||
| 
 | ||||
| #begin Audio/Score.wav | ||||
| /importer:WavImporter | ||||
| /processor:SoundEffectProcessor | ||||
| /processorParam:Quality=Best | ||||
| /build:Audio/Score.wav | ||||
| 
 | ||||
| #begin Audio/Win.wav | ||||
| /importer:WavImporter | ||||
| /processor:SoundEffectProcessor | ||||
| /processorParam:Quality=Best | ||||
| /build:Audio/Win.wav | ||||
| 
 | ||||
| #begin Audio/TimerTick.wav | ||||
| /importer:WavImporter | ||||
| /processor:SoundEffectProcessor | ||||
| /processorParam:Quality=Best | ||||
| /build:Audio/TimerTick.wav | ||||
| 
 | ||||
| #begin Audio/TimerEnd.wav | ||||
| /importer:WavImporter | ||||
| /processor:SoundEffectProcessor | ||||
| /processorParam:Quality=Best | ||||
| /build:Audio/TimerEnd.wav | ||||
| /build:Hit.wav | ||||
| 
 | ||||
| #begin UbuntuMono.spritefont | ||||
| /importer:FontDescriptionImporter | ||||
							
								
								
									
										
											BIN
										
									
								
								Game/Content/Hit.wav
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								Game/Content/Hit.wav
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										23
									
								
								Game/EngineConverter.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								Game/EngineConverter.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | ||||
| using System.Runtime.CompilerServices; | ||||
| using Microsoft.Xna.Framework; | ||||
| using Syntriax.Engine.Core; | ||||
|  | ||||
| namespace Pong; | ||||
|  | ||||
| public static class EngineConverter | ||||
| { | ||||
|     public readonly static Vector2D screenScale = Vector2D.Down + Vector2D.Right; | ||||
|  | ||||
|     [MethodImpl(MethodImplOptions.AggressiveInlining)] | ||||
|     public static EngineTime ToEngineTime(this GameTime gameTime) => new(gameTime.TotalGameTime, gameTime.ElapsedGameTime); | ||||
|     [MethodImpl(MethodImplOptions.AggressiveInlining)] | ||||
|     public static Vector2D ToVector2D(this Vector2 vector) => new(vector.X, vector.Y); | ||||
|     [MethodImpl(MethodImplOptions.AggressiveInlining)] | ||||
|     public static Vector2D ToVector2D(this Point point) => new(point.X, point.Y); | ||||
|     [MethodImpl(MethodImplOptions.AggressiveInlining)] | ||||
|     public static Vector2 ToVector2(this Vector2D vector) => new(vector.X, vector.Y); | ||||
|     [MethodImpl(MethodImplOptions.AggressiveInlining)] | ||||
|     public static Vector2 ToDisplayVector2(this Vector2D vector) => vector.Scale(screenScale).ToVector2(); | ||||
|     [MethodImpl(MethodImplOptions.AggressiveInlining)] | ||||
|     public static Vector2D ApplyDisplayScale(this Vector2D vector) => vector.Scale(screenScale); | ||||
| } | ||||
							
								
								
									
										37
									
								
								Game/Game.csproj
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								Game/Game.csproj
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,37 @@ | ||||
| <Project Sdk="Microsoft.NET.Sdk"> | ||||
|   <PropertyGroup> | ||||
|     <OutputType>WinExe</OutputType> | ||||
|     <TargetFramework>net8.0</TargetFramework> | ||||
|     <RollForward>Major</RollForward> | ||||
|     <PublishReadyToRun>false</PublishReadyToRun> | ||||
|     <TieredCompilation>false</TieredCompilation> | ||||
|     <Nullable>enable</Nullable> | ||||
|   </PropertyGroup> | ||||
|   <PropertyGroup> | ||||
|     <ApplicationManifest>app.manifest</ApplicationManifest> | ||||
|     <ApplicationIcon>Icon.ico</ApplicationIcon> | ||||
|   </PropertyGroup> | ||||
|   <ItemGroup> | ||||
|     <None Remove="Icon.ico" /> | ||||
|     <None Remove="Icon.bmp" /> | ||||
|   </ItemGroup> | ||||
|   <ItemGroup> | ||||
|     <EmbeddedResource Include="Icon.ico" /> | ||||
|     <EmbeddedResource Include="Icon.bmp" /> | ||||
|   </ItemGroup> | ||||
|   <ItemGroup> | ||||
|     <PackageReference Include="Apos.Shapes" Version="0.2.3" /> | ||||
|     <PackageReference Include="LiteNetLib" Version="1.2.0" /> | ||||
|     <PackageReference Include="MonoGame.Framework.DesktopGL" Version="3.8.1.303" /> | ||||
|     <PackageReference Include="MonoGame.Content.Builder.Task" Version="3.8.1.303" /> | ||||
|   </ItemGroup> | ||||
|   <ItemGroup> | ||||
|     <ProjectReference Include="..\Engine\Engine.Core\Engine.Core.csproj" /> | ||||
|     <ProjectReference Include="..\Engine\Engine.Input\Engine.Input.csproj" /> | ||||
|     <ProjectReference Include="..\Engine\Engine.Physics2D\Engine.Physics2D.csproj" /> | ||||
|   </ItemGroup> | ||||
|   <Target Name="RestoreDotnetTools" BeforeTargets="Restore"> | ||||
|     <Message Text="Restoring dotnet tools" Importance="High" /> | ||||
|     <Exec Command="dotnet tool restore" /> | ||||
|   </Target> | ||||
| </Project> | ||||
							
								
								
									
										200
									
								
								Game/GamePong.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										200
									
								
								Game/GamePong.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,200 @@ | ||||
| using System; | ||||
|  | ||||
| using Microsoft.Xna.Framework; | ||||
| using Microsoft.Xna.Framework.Graphics; | ||||
| using Microsoft.Xna.Framework.Input; | ||||
|  | ||||
| using Apos.Shapes; | ||||
|  | ||||
| using Pong.Behaviours; | ||||
| using Syntriax.Engine.Network; | ||||
|  | ||||
| using Syntriax.Engine.Core; | ||||
| using Syntriax.Engine.Core.Abstract; | ||||
| using Syntriax.Engine.Physics2D; | ||||
| using Syntriax.Engine.Physics2D.Abstract; | ||||
| using Syntriax.Engine.Physics2D.Primitives; | ||||
|  | ||||
| namespace Pong; | ||||
|  | ||||
| public class GamePong : Game | ||||
| { | ||||
|     private readonly GraphicsDeviceManager graphics = null!; | ||||
|     private IPhysicsEngine2D physicsEngine = null!; | ||||
|     private SpriteBatch spriteBatch = null!; | ||||
|     private ShapeBatch shapeBatch = null!; | ||||
|  | ||||
|     private GameManager gameManager = null!; | ||||
|     private BehaviourCollector<IDisplayableSprite> displayableCollector = null!; | ||||
|     private BehaviourCollector<IDisplayableShape> displayableShapeCollector = null!; | ||||
|     private BehaviourCollector<IMonoGameContentLoader> monoGameContentLoaderCollector = null!; | ||||
|     private MonoGameCamera2DBehaviour cameraBehaviour = null!; | ||||
|  | ||||
|     private PongManagerBehaviour pongManager = null!; | ||||
|  | ||||
|     private float physicsTimer = 0f; | ||||
|  | ||||
|     public GamePong() | ||||
|     { | ||||
|         graphics = new GraphicsDeviceManager(this) | ||||
|         { | ||||
|             PreferredBackBufferWidth = 1024, | ||||
|             PreferredBackBufferHeight = 576, | ||||
|             GraphicsProfile = GraphicsProfile.HiDef | ||||
|         }; | ||||
|  | ||||
|         Content.RootDirectory = "Content"; | ||||
|         IsMouseVisible = true; | ||||
|     } | ||||
|  | ||||
|     protected override void Initialize() | ||||
|     { | ||||
|         // TODO: Add your initialization logic here | ||||
|         gameManager = new(); | ||||
|         displayableCollector = new(gameManager); | ||||
|         displayableShapeCollector = new(gameManager); | ||||
|         monoGameContentLoaderCollector = new(gameManager); | ||||
|         physicsEngine = new PhysicsEngine2DCollector(gameManager) { IterationPerStep = 3 }; | ||||
|  | ||||
|         monoGameContentLoaderCollector.OnCollected += (_, cached) => cached.LoadContent(Content); | ||||
|  | ||||
|         gameManager.Initialize(); | ||||
|  | ||||
|         base.Initialize(); | ||||
|     } | ||||
|  | ||||
|     protected override void LoadContent() | ||||
|     { | ||||
|         spriteBatch = new SpriteBatch(GraphicsDevice); | ||||
|         shapeBatch = new ShapeBatch(GraphicsDevice, Content); | ||||
|         SpriteFont spriteFont = Content.Load<SpriteFont>("UbuntuMono"); | ||||
|  | ||||
|         //////////////////////////////////////////////////////////////////////////////////// | ||||
|  | ||||
|         string[] commandLineArguments = Environment.GetCommandLineArgs(); | ||||
|         if (commandLineArguments.Length != 1) | ||||
|         { | ||||
|             if (commandLineArguments[1].Equals("server", StringComparison.OrdinalIgnoreCase)) | ||||
|             { | ||||
|                 gameManager.InstantiateGameObject().BehaviourController.AddBehaviour<NetworkServer>().Start(8888, 2); | ||||
|                 Window.Title = "Pong - Server"; | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 Window.Title = $"Pong - Client -> {commandLineArguments[1]}"; | ||||
|                 gameManager.InstantiateGameObject().BehaviourController.AddBehaviour<NetworkClient>().Connect(commandLineArguments[1], 8888); | ||||
|             } | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             gameManager.InstantiateGameObject().BehaviourController.AddBehaviour<NetworkClient>().Connect("127.0.0.1", 8888); | ||||
|             Window.Title = $"Pong - Client -> 127.0.0.1"; | ||||
|         } | ||||
|  | ||||
|         //////////////////////////////////////////////////////////////////////////////////// | ||||
|  | ||||
|         IGameObject gameObjectCamera = gameManager.InstantiateGameObject().SetGameObject("Camera"); ; | ||||
|         gameObjectCamera.BehaviourController.AddBehaviour<CameraController>(); | ||||
|         cameraBehaviour = gameObjectCamera.BehaviourController.AddBehaviour<MonoGameCamera2DBehaviour>(graphics); | ||||
|  | ||||
|         //////////////////////////////////////////////////////////////////////////////////// | ||||
|  | ||||
|         IGameObject gameObjectPongManager = gameManager.InstantiateGameObject().SetGameObject("Pong Game Manager"); | ||||
|         pongManager = gameObjectPongManager.BehaviourController.AddBehaviour<PongManagerBehaviour>(5); | ||||
|         pongManager.Id = "pongManager"; | ||||
|  | ||||
|         //////////////////////////////////////////////////////////////////////////////////// | ||||
|  | ||||
|         IGameObject gameObjectBall = gameManager.InstantiateGameObject().SetGameObject("Ball"); | ||||
|         gameObjectBall.Transform.SetTransform(position: new Vector2D(0, 0f), scale: new Vector2D(10f, 10f)); | ||||
|  | ||||
|         gameObjectBall.BehaviourController.AddBehaviour<CircleBehaviour>(new Circle(Vector2D.Zero, 1f)); | ||||
|         gameObjectBall.BehaviourController.AddBehaviour<BallBehaviour>().Id = "ball"; | ||||
|         gameObjectBall.BehaviourController.AddBehaviour<RigidBody2D>(); | ||||
|  | ||||
|         //////////////////////////////////////////////////////////////////////////////////// | ||||
|  | ||||
|         IGameObject gameObjectLeftPaddle = gameManager.InstantiateGameObject().SetGameObject("Left Paddle"); | ||||
|         gameObjectLeftPaddle.Transform.SetTransform(position: new Vector2D(-468f, 0f), scale: new Vector2D(15f, 60f)); | ||||
|  | ||||
|         gameObjectLeftPaddle.BehaviourController.AddBehaviour<NetworkedKeyboardInputs>().Id = "leftPaddleInput"; | ||||
|         gameObjectLeftPaddle.BehaviourController.AddBehaviour<PaddleBehaviour>(Keys.W, Keys.S, 228f, -228f, 400f).Id = "leftPaddle"; | ||||
|         gameObjectLeftPaddle.BehaviourController.AddBehaviour<ShapeBehaviour>(Shape.Box); | ||||
|         gameObjectLeftPaddle.BehaviourController.AddBehaviour<RigidBody2D>().IsStatic = true; | ||||
|  | ||||
|         IGameObject gameObjectRightPaddle = gameManager.InstantiateGameObject().SetGameObject("Right Paddle"); | ||||
|         gameObjectRightPaddle.Transform.SetTransform(position: new Vector2D(468f, 0f), scale: new Vector2D(15f, 60f)); | ||||
|         gameObjectRightPaddle.BehaviourController.AddBehaviour<NetworkedKeyboardInputs>().Id = "rightPaddleInput"; | ||||
|         gameObjectRightPaddle.BehaviourController.AddBehaviour<PaddleBehaviour>(Keys.Up, Keys.Down, 228f, -228f, 400f).Id = "rightPaddle"; | ||||
|         gameObjectRightPaddle.BehaviourController.AddBehaviour<ShapeBehaviour>(Shape.Box); | ||||
|         gameObjectRightPaddle.BehaviourController.AddBehaviour<RigidBody2D>().IsStatic = true; | ||||
|  | ||||
|         //////////////////////////////////////////////////////////////////////////////////// | ||||
|  | ||||
|         IGameObject gameObjectWallTop = gameManager.InstantiateGameObject().SetGameObject("Wall Top"); | ||||
|         gameObjectWallTop.Transform.SetTransform(position: new Vector2D(0f, 308f), scale: new Vector2D(552f, 20f)); | ||||
|         gameObjectWallTop.BehaviourController.AddBehaviour<ShapeBehaviour>(Shape.Box); | ||||
|         gameObjectWallTop.BehaviourController.AddBehaviour<RigidBody2D>().IsStatic = true; | ||||
|  | ||||
|         IGameObject gameObjectWallBottom = gameManager.InstantiateGameObject().SetGameObject("Wall Bottom"); | ||||
|         gameObjectWallBottom.Transform.SetTransform(position: new Vector2D(0f, -308f), scale: new Vector2D(552f, 20f)); | ||||
|         gameObjectWallBottom.BehaviourController.AddBehaviour<ShapeBehaviour>(Shape.Box); | ||||
|         gameObjectWallBottom.BehaviourController.AddBehaviour<RigidBody2D>().IsStatic = true; | ||||
|  | ||||
|         IGameObject gameObjectWallRight = gameManager.InstantiateGameObject().SetGameObject("Wall Right"); | ||||
|         gameObjectWallRight.Transform.SetTransform(position: new Vector2D(532f, 0f), scale: new Vector2D(20f, 328f)); | ||||
|         gameObjectWallRight.BehaviourController.AddBehaviour<WallScoreBehaviour>((Action)pongManager.ScoreToLeft); | ||||
|         gameObjectWallRight.BehaviourController.AddBehaviour<ShapeBehaviour>(Shape.Box); | ||||
|         gameObjectWallRight.BehaviourController.AddBehaviour<RigidBody2D>().IsStatic = true; | ||||
|  | ||||
|         IGameObject gameObjectWallLeft = gameManager.InstantiateGameObject().SetGameObject("Wall Left"); | ||||
|         gameObjectWallLeft.Transform.SetTransform(position: new Vector2D(-532f, 0f), scale: new Vector2D(20f, 328f)); | ||||
|         gameObjectWallLeft.BehaviourController.AddBehaviour<WallScoreBehaviour>((Action)pongManager.ScoreToRight); | ||||
|         gameObjectWallLeft.BehaviourController.AddBehaviour<ShapeBehaviour>(Shape.Box); | ||||
|         gameObjectWallLeft.BehaviourController.AddBehaviour<RigidBody2D>().IsStatic = true; | ||||
|  | ||||
|         //////////////////////////////////////////////////////////////////////////////////// | ||||
|  | ||||
|         IGameObject gameObjectLeftScoreText = gameManager.InstantiateGameObject().SetGameObject("Score Left"); | ||||
|         gameObjectLeftScoreText.Transform.SetTransform(position: new Vector2D(-250f, 250f), scale: Vector2D.One * .25f); | ||||
|         gameObjectLeftScoreText.BehaviourController.AddBehaviour<TextScoreBehaviour>(true, spriteFont); | ||||
|  | ||||
|         IGameObject gameObjectRightScoreText = gameManager.InstantiateGameObject().SetGameObject("Score Right"); | ||||
|         gameObjectRightScoreText.Transform.SetTransform(position: new Vector2D(250f, 250f), scale: Vector2D.One * .25f); | ||||
|         gameObjectRightScoreText.BehaviourController.AddBehaviour<TextScoreBehaviour>(false, spriteFont); | ||||
|     } | ||||
|  | ||||
|     protected override void Update(GameTime gameTime) | ||||
|     { | ||||
|         if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape)) | ||||
|             Exit(); | ||||
|  | ||||
|         gameManager.Update(gameTime.ToEngineTime()); | ||||
|         while (physicsTimer + 0.01f < gameTime.TotalGameTime.TotalMilliseconds * .001f)//seconds) | ||||
|         { | ||||
|             physicsTimer += 0.01f; | ||||
|             physicsEngine.Step(.01f); | ||||
|         } | ||||
|         base.Update(gameTime); | ||||
|     } | ||||
|  | ||||
|     protected override void Draw(GameTime gameTime) | ||||
|     { | ||||
|         GraphicsDevice.Clear(new Color() { R = 32, G = 32, B = 32 }); | ||||
|  | ||||
|         // TODO: Add your drawing code here | ||||
|         gameManager.PreDraw(); | ||||
|  | ||||
|         spriteBatch.Begin(SpriteSortMode.Deferred, transformMatrix: cameraBehaviour.MatrixTransform); | ||||
|         foreach (var displayable in displayableCollector) | ||||
|             displayable.Draw(spriteBatch); | ||||
|         spriteBatch.End(); | ||||
|  | ||||
|         shapeBatch.Begin(cameraBehaviour.MatrixTransform); | ||||
|         foreach (var displayableShape in displayableShapeCollector) | ||||
|             displayableShape.Draw(shapeBatch); | ||||
|         shapeBatch.End(); | ||||
|  | ||||
|         base.Draw(gameTime); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										
											BIN
										
									
								
								Game/Icon.bmp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								Game/Icon.bmp
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 256 KiB | 
							
								
								
									
										
											BIN
										
									
								
								Game/Icon.ico
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								Game/Icon.ico
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 144 KiB | 
							
								
								
									
										18
									
								
								Game/Network/Abstract/INetworkBehaviour.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								Game/Network/Abstract/INetworkBehaviour.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | ||||
| using Syntriax.Engine.Core.Abstract; | ||||
|  | ||||
| namespace Syntriax.Engine.Network.Abstract; | ||||
|  | ||||
| public interface INetworkBehaviour : IBehaviour | ||||
| { | ||||
|     int NetworkId { get; } | ||||
|  | ||||
|     bool LocalAssigned { get; } | ||||
|  | ||||
|     bool IsServer { get; } | ||||
|     bool IsClient { get; } | ||||
|  | ||||
|     INetworkCommunicator NetworkCommunicator { get; } | ||||
|  | ||||
|     public void RequestAssignment(); | ||||
|     public void ReleaseAssignment(); | ||||
| } | ||||
							
								
								
									
										6
									
								
								Game/Network/Abstract/INetworkClient.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								Game/Network/Abstract/INetworkClient.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | ||||
| namespace Syntriax.Engine.Network.Abstract; | ||||
|  | ||||
| public interface INetworkClient : INetworkCommunicator | ||||
| { | ||||
|     void Connect(string address, int port, string? password = null); | ||||
| } | ||||
							
								
								
									
										22
									
								
								Game/Network/Abstract/INetworkCommunicator.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								Game/Network/Abstract/INetworkCommunicator.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | ||||
| using System; | ||||
|  | ||||
| using LiteNetLib; | ||||
| using LiteNetLib.Utils; | ||||
|  | ||||
| using Syntriax.Engine.Core.Abstract; | ||||
|  | ||||
| namespace Syntriax.Engine.Network.Abstract; | ||||
|  | ||||
| public interface INetworkCommunicator | ||||
| { | ||||
|     EventBasedNetListener Listener { get; } | ||||
|     NetManager Manager { get; } | ||||
|  | ||||
|     void PollEvents(); | ||||
|     void Stop(); | ||||
|  | ||||
|     void RegisterEntityListener(IEntity entity, Action<NetPacketReader, NetPeer> onDataReceived); | ||||
|     void UnregisterEntityListener(IEntity entity); | ||||
|     NetDataWriter GetEntityWriter(IEntity entity); | ||||
|     NetDataWriter GetMessageWriter(IEntity entity); | ||||
| } | ||||
							
								
								
									
										11
									
								
								Game/Network/Abstract/INetworkEntity.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								Game/Network/Abstract/INetworkEntity.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | ||||
| using System; | ||||
|  | ||||
| namespace Syntriax.Engine.Network.Abstract; | ||||
|  | ||||
| internal interface INetworkEntity | ||||
| { | ||||
|     Action<INetworkEntity, int> OnNetworkIdChanged { get; set; } | ||||
|     int NetworkId { get; set; } | ||||
|  | ||||
|     void SetNetworkId(int id); | ||||
| } | ||||
							
								
								
									
										10
									
								
								Game/Network/Abstract/INetworkManager.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								Game/Network/Abstract/INetworkManager.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | ||||
| namespace Syntriax.Engine.Network.Abstract; | ||||
|  | ||||
| public interface INetworkManager | ||||
| { | ||||
|     // Action<IGameObject>? OnNetworkGameObjectInstantiated { get; set; } | ||||
|  | ||||
|     INetworkCommunicator NetworkCommunicator { get; } | ||||
|  | ||||
|     // Task<T> Instantiate<T>(params object?[]? args) where T : class, IGameObject; | ||||
| } | ||||
							
								
								
									
										10
									
								
								Game/Network/Abstract/INetworkServer.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								Game/Network/Abstract/INetworkServer.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | ||||
| namespace Syntriax.Engine.Network.Abstract; | ||||
|  | ||||
| public interface INetworkServer : INetworkCommunicator | ||||
| { | ||||
|     string Password { get; } | ||||
|     int MaxConnectionCount { get; } | ||||
|     int Port { get; } | ||||
|  | ||||
|     void Start(int port, int maxConnectionCount, string? password = null); | ||||
| } | ||||
							
								
								
									
										81
									
								
								Game/Network/NetworkBase.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								Game/Network/NetworkBase.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,81 @@ | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
|  | ||||
| using LiteNetLib; | ||||
| using LiteNetLib.Utils; | ||||
|  | ||||
| using Syntriax.Engine.Core; | ||||
| using Syntriax.Engine.Core.Abstract; | ||||
| using Syntriax.Engine.Network.Abstract; | ||||
|  | ||||
| namespace Syntriax.Engine.Network; | ||||
|  | ||||
| public abstract class NetworkBase : BehaviourOverride, INetworkCommunicator | ||||
| { | ||||
|     public EventBasedNetListener Listener { get; private set; } = null!; | ||||
|     public NetManager Manager { get; private set; } = null!; | ||||
|  | ||||
|     public NetworkBase() | ||||
|     { | ||||
|         Priority = 10; | ||||
|  | ||||
|         Listener = new EventBasedNetListener(); | ||||
|         Manager = new NetManager(Listener); | ||||
|  | ||||
|         Listener.NetworkReceiveEvent += NetworkReceiveEvent; | ||||
|     } | ||||
|  | ||||
|     public void PollEvents() => Manager.PollEvents(); | ||||
|     public void Stop() => Manager.Stop(); | ||||
|  | ||||
|     protected override void OnUpdate() => PollEvents(); | ||||
|     protected override void OnFinalize() => Stop(); | ||||
|  | ||||
|     private readonly Dictionary<string, Action<NetPacketReader, NetPeer>> callbacks = new(32); | ||||
|  | ||||
|     private void NetworkReceiveEvent(NetPeer peer, NetPacketReader reader, byte channel, DeliveryMethod deliveryMethod) | ||||
|     { | ||||
|         if (callbacks.TryGetValue(reader.GetString(), out var action)) | ||||
|             action?.Invoke(reader, peer); | ||||
|  | ||||
|         reader.Recycle(); | ||||
|     } | ||||
|  | ||||
|     public void RegisterEntityListener(IEntity entity, Action<NetPacketReader, NetPeer> onDataReceived) | ||||
|     { | ||||
|         if (callbacks.ContainsKey(entity.Id)) | ||||
|             return; | ||||
|  | ||||
|         callbacks.Add(entity.Id, onDataReceived); | ||||
|         entity.OnIdChanged += OnEntityIdChanged; | ||||
|     } | ||||
|  | ||||
|     public void UnregisterEntityListener(IEntity entity) | ||||
|     { | ||||
|         if (!callbacks.Remove(entity.Id)) | ||||
|             return; | ||||
|  | ||||
|         entity.OnIdChanged -= OnEntityIdChanged; | ||||
|     } | ||||
|  | ||||
|     public NetDataWriter GetMessageWriter(IEntity entity) | ||||
|     { | ||||
|         NetDataWriter netDataWriter = GetEntityWriter(entity); | ||||
|         netDataWriter.Put((int)MessageType.Message); | ||||
|         return netDataWriter; | ||||
|     } | ||||
|  | ||||
|     public NetDataWriter GetEntityWriter(IEntity entity) | ||||
|     { | ||||
|         NetDataWriter netDataWriter = new(); | ||||
|         netDataWriter.Put(entity.Id); | ||||
|         return netDataWriter; | ||||
|     } | ||||
|  | ||||
|     private void OnEntityIdChanged(IEntity entity, string previousId) | ||||
|     { | ||||
|         var action = callbacks[previousId]; | ||||
|         callbacks.Remove(previousId); | ||||
|         callbacks.Add(entity.Id, action); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										99
									
								
								Game/Network/NetworkBehaviour.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										99
									
								
								Game/Network/NetworkBehaviour.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,99 @@ | ||||
| using System; | ||||
|  | ||||
| using LiteNetLib; | ||||
|  | ||||
| using Syntriax.Engine.Core; | ||||
| using Syntriax.Engine.Network.Abstract; | ||||
|  | ||||
| namespace Syntriax.Engine.Network; | ||||
|  | ||||
| public abstract class NetworkBehaviour : BehaviourOverride, INetworkBehaviour | ||||
| { | ||||
|     public int NetworkId { get; private set; } = 0; | ||||
|  | ||||
|     public bool LocalAssigned { get; private set; } = false; | ||||
|  | ||||
|     public bool IsServer { get; private set; } = false; | ||||
|     public bool IsClient { get; private set; } = false; | ||||
|  | ||||
|     public INetworkCommunicator NetworkCommunicator { get; private set; } = null!; | ||||
|  | ||||
|     protected override void OnInitialize() | ||||
|     { | ||||
|         NetworkCommunicator = BehaviourController.GetBehaviourInParent<INetworkCommunicator>() | ||||
|                               ?? GameObject.GameManager.FindBehaviour<INetworkCommunicator>() | ||||
|                               ?? throw new Exception($"Could not find an {nameof(INetworkCommunicator)}."); | ||||
|  | ||||
|         NetworkCommunicator.RegisterEntityListener(this, OnMessageReceivedInternal); | ||||
|  | ||||
|         if (NetworkCommunicator is INetworkClient client) | ||||
|         { | ||||
|             IsClient = true; | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         IsServer = true; | ||||
|         LocalAssigned = true; | ||||
|     } | ||||
|  | ||||
|     public void ReleaseAssignment() | ||||
|     { | ||||
|         if (IsServer) | ||||
|             return; | ||||
|  | ||||
|         var netDataWriter = NetworkCommunicator.GetEntityWriter(this); | ||||
|         netDataWriter.Put((int)MessageType.AssignmentRelease); | ||||
|         NetworkCommunicator.Manager.SendToAll(netDataWriter, DeliveryMethod.ReliableOrdered); | ||||
|     } | ||||
|  | ||||
|     public void RequestAssignment() | ||||
|     { | ||||
|         if (IsServer) | ||||
|             return; | ||||
|  | ||||
|         var netDataWriter = NetworkCommunicator.GetEntityWriter(this); | ||||
|         netDataWriter.Put((int)MessageType.AssignmentRequest); | ||||
|         NetworkCommunicator.Manager.SendToAll(netDataWriter, DeliveryMethod.ReliableOrdered); | ||||
|     } | ||||
|  | ||||
|     protected abstract void OnMessageReceived(NetPacketReader reader, NetPeer peer); | ||||
|     private void OnMessageReceivedInternal(NetPacketReader reader, NetPeer peer) | ||||
|     { | ||||
|         MessageType messageType = (MessageType)reader.GetInt(); | ||||
|  | ||||
|         if (IsServer) | ||||
|         { | ||||
|             switch (messageType) | ||||
|             { | ||||
|                 case MessageType.Message: OnMessageReceived(reader, peer); break; | ||||
|                 case MessageType.AssignmentRequest: | ||||
|                 case MessageType.AssignmentRelease: | ||||
|                     var netDataWriter = NetworkCommunicator.GetEntityWriter(this); | ||||
|                     netDataWriter.Put((int)(messageType == MessageType.AssignmentRequest ? MessageType.Assigned : MessageType.Unassigned)); | ||||
|                     peer.Send(netDataWriter, DeliveryMethod.ReliableOrdered); | ||||
|                     break; | ||||
|                 default: | ||||
|                     break; | ||||
|             } | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         switch (messageType) | ||||
|         { | ||||
|             case MessageType.Message: OnMessageReceived(reader, peer); break; | ||||
|             case MessageType.Assigned: LocalAssigned = true; break; | ||||
|             case MessageType.Unassigned: LocalAssigned = false; break; | ||||
|             default: | ||||
|                 break; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| internal enum MessageType | ||||
| { | ||||
|     Message, | ||||
|     AssignmentRequest, | ||||
|     AssignmentRelease, | ||||
|     Assigned, | ||||
|     Unassigned, | ||||
| } | ||||
							
								
								
									
										12
									
								
								Game/Network/NetworkClient.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								Game/Network/NetworkClient.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | ||||
| using Syntriax.Engine.Network.Abstract; | ||||
|  | ||||
| namespace Syntriax.Engine.Network; | ||||
|  | ||||
| public class NetworkClient : NetworkBase, INetworkClient | ||||
| { | ||||
|     public void Connect(string address, int port, string? password = null) | ||||
|     { | ||||
|         Manager.Start(); | ||||
|         Manager.Connect(address, port, password ?? string.Empty); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										20
									
								
								Game/Network/NetworkExtensions.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								Game/Network/NetworkExtensions.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | ||||
| using LiteNetLib; | ||||
| using LiteNetLib.Utils; | ||||
|  | ||||
| using Syntriax.Engine.Core; | ||||
|  | ||||
| namespace Syntriax.Engine.Network; | ||||
|  | ||||
| public static class NetworkExtensions | ||||
| { | ||||
|     public static Vector2D GetVector2D(this NetPacketReader reader) | ||||
|         => new(reader.GetFloat(), reader.GetFloat()); | ||||
|     public static void GetVector2D(this NetPacketReader reader, out Vector2D vector2D) | ||||
|         => vector2D = new(reader.GetFloat(), reader.GetFloat()); | ||||
|  | ||||
|     public static void Put(this NetDataWriter writer, Vector2D vector) | ||||
|     { | ||||
|         writer.Put(vector.X); | ||||
|         writer.Put(vector.Y); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										31
									
								
								Game/Network/NetworkManager.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								Game/Network/NetworkManager.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,31 @@ | ||||
| using LiteNetLib; | ||||
| using Syntriax.Engine.Core; | ||||
|  | ||||
| using Syntriax.Engine.Network.Abstract; | ||||
|  | ||||
| namespace Syntriax.Engine.Network; | ||||
|  | ||||
| public class NetworkManager : NetworkBehaviour, INetworkManager | ||||
| { | ||||
|     private BehaviourCollector<INetworkEntity> entities = null!; | ||||
|  | ||||
|     private static int networkIdIndex = 0; | ||||
|  | ||||
|     protected override void OnInitialize() | ||||
|     { | ||||
|         base.OnInitialize(); | ||||
|  | ||||
|         ((INetworkEntity)this).SetNetworkId(networkIdIndex++); | ||||
|  | ||||
|         entities = new(GameObject.GameManager); | ||||
|         foreach (var entity in entities) | ||||
|             entity.SetNetworkId(networkIdIndex++); | ||||
|  | ||||
|         entities.OnCollected += OnCollected; | ||||
|     } | ||||
|  | ||||
|     private void OnCollected(BehaviourCollector<INetworkEntity> collector, INetworkEntity entity) | ||||
|         => entity.SetNetworkId(networkIdIndex++); | ||||
|  | ||||
|     protected override void OnMessageReceived(NetPacketReader reader, NetPeer peer) { } | ||||
| } | ||||
							
								
								
									
										30
									
								
								Game/Network/NetworkServer.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								Game/Network/NetworkServer.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,30 @@ | ||||
| using Syntriax.Engine.Network.Abstract; | ||||
|  | ||||
| namespace Syntriax.Engine.Network; | ||||
|  | ||||
| public class NetworkServer : NetworkBase, INetworkServer | ||||
| { | ||||
|     public string Password { get; private set; } = string.Empty; | ||||
|     public int MaxConnectionCount { get; private set; } = 0; | ||||
|     public int Port { get; private set; } = 8888; | ||||
|  | ||||
|     public NetworkServer() : base() | ||||
|     { | ||||
|         Listener.ConnectionRequestEvent += request => | ||||
|         { | ||||
|             if (Manager.ConnectedPeersCount < MaxConnectionCount) | ||||
|                 request.AcceptIfKey(Password); | ||||
|             else | ||||
|                 request.Reject(); | ||||
|         }; | ||||
|     } | ||||
|  | ||||
|     public void Start(int port, int maxConnectionCount, string? password = null) | ||||
|     { | ||||
|         Password = password ?? string.Empty; | ||||
|         MaxConnectionCount = maxConnectionCount; | ||||
|         Port = port; | ||||
|  | ||||
|         Manager.Start(port); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										3
									
								
								Game/Program.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								Game/Program.cs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | ||||
|  | ||||
| using var game = new Pong.GamePong(); | ||||
| game.Run(); | ||||
| @@ -1,6 +1,6 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1"> | ||||
|   <assemblyIdentity version="1.0.0.0" name="Desktop"/> | ||||
|   <assemblyIdentity version="1.0.0.0" name="Game"/> | ||||
|   <trustInfo xmlns="urn:schemas-microsoft-com:asm.v2"> | ||||
|     <security> | ||||
|       <requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3"> | ||||
| @@ -1,11 +0,0 @@ | ||||
| public class ClientConfiguration | ||||
| { | ||||
|     public bool Host = false; | ||||
|     public int HostPort = 8888; | ||||
|  | ||||
|     public string ServerAddress = "localhost"; | ||||
|     public int ServerPort = 8888; | ||||
|  | ||||
|     public int windowWidth = 1024; | ||||
|     public int windowHeight = 576; | ||||
| } | ||||
| @@ -1,15 +0,0 @@ | ||||
|  | ||||
| #----------------------------- Global Properties ----------------------------# | ||||
|  | ||||
| /outputDir:bin/$(Platform) | ||||
| /intermediateDir:obj/$(Platform) | ||||
| /platform:DesktopGL | ||||
| /config: | ||||
| /profile:Reach | ||||
| /compress:False | ||||
|  | ||||
| #-------------------------------- References --------------------------------# | ||||
|  | ||||
|  | ||||
| #---------------------------------- Content ---------------------------------# | ||||
|  | ||||
| @@ -1,90 +0,0 @@ | ||||
| <Project Sdk="Microsoft.NET.Sdk"> | ||||
|   <PropertyGroup> | ||||
|     <OutputType>WinExe</OutputType> | ||||
|     <TargetFramework>net9.0</TargetFramework> | ||||
|     <RollForward>Major</RollForward> | ||||
|     <PublishReadyToRun>false</PublishReadyToRun> | ||||
|     <TieredCompilation>false</TieredCompilation> | ||||
|     <Nullable>enable</Nullable> | ||||
|     <RootNamespace>Pong.Platforms.Desktop</RootNamespace> | ||||
|     <AssemblyName>Pong</AssemblyName> | ||||
|   </PropertyGroup> | ||||
|   <PropertyGroup> | ||||
|     <ApplicationManifest>app.manifest</ApplicationManifest> | ||||
|     <ApplicationIcon>Icon.ico</ApplicationIcon> | ||||
|   </PropertyGroup> | ||||
|   <ItemGroup> | ||||
|     <None Remove="Icon.ico" /> | ||||
|     <None Remove="Icon.bmp" /> | ||||
|   </ItemGroup> | ||||
|   <ItemGroup> | ||||
|     <EmbeddedResource Include="Icon.ico"> | ||||
|       <LogicalName>Icon.ico</LogicalName> | ||||
|     </EmbeddedResource> | ||||
|     <EmbeddedResource Include="Icon.bmp"> | ||||
|       <LogicalName>Icon.bmp</LogicalName> | ||||
|     </EmbeddedResource> | ||||
|   </ItemGroup> | ||||
|   <ItemGroup> | ||||
|     <PackageReference Include="MonoGame.Framework.DesktopGL" Version="3.8.2.1105" /> | ||||
|     <PackageReference Include="MonoGame.Content.Builder.Task" Version="3.8.2.1105" /> | ||||
|     <PackageReference Include="nulastudio.NetBeauty" Version="2.1.5" /> | ||||
|   </ItemGroup> | ||||
|   <ItemGroup> | ||||
|     <ProjectReference Include="../../Shared/Shared.csproj" /> | ||||
|   </ItemGroup> | ||||
|  | ||||
|   <ItemGroup> | ||||
|     <MonoGameContentReference Include="../../Shared/Content/Content.mgcb"> | ||||
|       <Link>Content/Content.mgcb</Link> | ||||
|     </MonoGameContentReference> | ||||
|   </ItemGroup> | ||||
|   <ItemGroup> | ||||
|     <ProjectReference Include="../../Shared/Shared.csproj" /> | ||||
|     <ProjectReference Include="..\..\Engine\Engine.Integration\Engine.Integration.Yaml\Engine.Integration.Yaml.csproj" /> | ||||
|   </ItemGroup> | ||||
|   <Target Name="RestoreDotnetTools" BeforeTargets="Restore"> | ||||
|     <Message Text="Restoring dotnet tools" Importance="High" /> | ||||
|     <Exec Command="dotnet tool restore" /> | ||||
|   </Target> | ||||
|  | ||||
|   <PropertyGroup> | ||||
|     <BeautySharedRuntimeMode>False</BeautySharedRuntimeMode> | ||||
|     <!-- beauty into sub-directory, default is libs, quote with "" if contains space  --> | ||||
|     <BeautyLibsDir Condition="$(BeautySharedRuntimeMode) == 'True'">../Libraries</BeautyLibsDir> | ||||
|     <BeautyLibsDir Condition="$(BeautySharedRuntimeMode) != 'True'">./Libraries</BeautyLibsDir> | ||||
|     <!-- dlls that you don't want to be moved or can not be moved --> | ||||
|     <!-- <BeautyExcludes>dll1.dll;lib*;...</BeautyExcludes> --> | ||||
|     <BeautyExcludes>SDL2.dll</BeautyExcludes> | ||||
|     <!-- dlls that end users never needed, so hide them --> | ||||
|     <BeautyHiddens>hostfxr;hostpolicy;*.deps.json;*.runtimeconfig*.json</BeautyHiddens> | ||||
|     <!-- set to True if you want to disable --> | ||||
|     <DisableBeauty>False</DisableBeauty> | ||||
|     <!-- set to False if you want to beauty on build --> | ||||
|     <BeautyOnPublishOnly>False</BeautyOnPublishOnly> | ||||
|     <!-- DO NOT TOUCH THIS OPTION --> | ||||
|     <BeautyNoRuntimeInfo>False</BeautyNoRuntimeInfo> | ||||
|     <!-- valid values: auto|with|without --> | ||||
|     <BeautyNBLoaderVerPolicy>auto</BeautyNBLoaderVerPolicy> | ||||
|     <!-- set to True if you want to allow 3rd debuggers(like dnSpy) debugs the app --> | ||||
|     <BeautyEnableDebugging>False</BeautyEnableDebugging> | ||||
|     <!-- the patch can reduce the file count --> | ||||
|     <!-- set to False if you want to disable --> | ||||
|     <!-- SCD Mode Feature Only --> | ||||
|     <BeautyUsePatch>True</BeautyUsePatch> | ||||
|     <!-- App Entry Dll = BeautyDir + BeautyAppHostDir + BeautyAppHostEntry --> | ||||
|     <!-- see https://github.com/nulastudio/NetBeauty2#customize-apphost for more details --> | ||||
|     <!-- relative path based on AppHostDir --> | ||||
|     <!-- .NET Core Non Single-File Only --> | ||||
|     <!-- <BeautyAppHostEntry>bin/MyApp.dll</BeautyAppHostEntry> --> | ||||
|     <!-- relative path based on BeautyDir --> | ||||
|     <!-- .NET Core Non Single-File Only --> | ||||
|     <!-- <BeautyAppHostDir>..</BeautyAppHostDir> --> | ||||
|     <!-- <BeautyAfterTasks></BeautyAfterTasks> --> | ||||
|     <!-- valid values: Error|Detail|Info --> | ||||
|     <BeautyLogLevel>Info</BeautyLogLevel> | ||||
|     <!-- set to a repo mirror if you have troble in connecting github --> | ||||
|     <!-- <BeautyGitCDN>https://gitee.com/liesauer/HostFXRPatcher</BeautyGitCDN> --> | ||||
|     <!-- <BeautyGitTree>master</BeautyGitTree> --> | ||||
|   </PropertyGroup> | ||||
| </Project> | ||||
										
											Binary file not shown.
										
									
								
							| Before Width: | Height: | Size: 192 KiB | 
										
											Binary file not shown.
										
									
								
							| Before Width: | Height: | Size: 7.2 KiB | 
										
											Binary file not shown.
										
									
								
							| Before Width: | Height: | Size: 7.2 KiB | 
| @@ -1,74 +0,0 @@ | ||||
| using System; | ||||
| using System.IO; | ||||
|  | ||||
| using Microsoft.Xna.Framework.Graphics; | ||||
|  | ||||
| using Engine.Core; | ||||
| using Engine.Core.Debug; | ||||
| using Engine.Core.Serialization; | ||||
| using Engine.Integration.MonoGame; | ||||
| using Engine.Serializers.Yaml; | ||||
|  | ||||
| Universe universe = new(); | ||||
|  | ||||
| ISerializer serializer = new YamlSerializer(); | ||||
|  | ||||
| ILogger logger = new FileLogger($"Logs/{DateTime.UtcNow:yyyy-MM-dd_HH-mm-ss-ffffff}.log"); | ||||
|  | ||||
| #if DEBUG | ||||
| logger = new LoggerWrapper(logger, new ConsoleLogger()); | ||||
| #endif | ||||
|  | ||||
| universe.InstantiateUniverseObject().SetUniverseObject("Logger").BehaviourController.AddBehaviour<LoggerContainer>().Logger = ILogger.Shared = logger; | ||||
|  | ||||
| string settingsPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "settings.yaml"); | ||||
| ClientConfiguration clientConfiguration = GetOrCreateConfiguration(serializer, logger, settingsPath); | ||||
|  | ||||
| if (clientConfiguration.Host) | ||||
|     Pong.PongUniverse.ApplyPongServer(universe, clientConfiguration.HostPort); | ||||
|  | ||||
| Pong.PongUniverse.ApplyPongClient(universe, clientConfiguration.ServerAddress, clientConfiguration.ServerPort); | ||||
| Pong.PongUniverse.ApplyPongUniverse(universe); | ||||
|  | ||||
| universe.InstantiateUniverseObject().SetUniverseObject("Desktop HO") | ||||
|     .BehaviourController.AddBehaviour<KeyboardInputs>(); | ||||
|  | ||||
| using MonoGameWindow monoGameWindow = new(universe); | ||||
|  | ||||
| monoGameWindow.Graphics.PreferredBackBufferWidth = clientConfiguration.windowWidth; | ||||
| monoGameWindow.Graphics.PreferredBackBufferHeight = clientConfiguration.windowHeight; | ||||
| monoGameWindow.Graphics.GraphicsProfile = GraphicsProfile.HiDef; | ||||
|  | ||||
| universe.FindBehaviour<Engine.Systems.Network.INetworkCommunicatorClient>()? | ||||
|     .OnConnectionEstablished.AddOneTimeListener( | ||||
|         (sender, connection) => monoGameWindow.Window.Title = $"Client {connection.Id}" | ||||
|     ); | ||||
|  | ||||
| monoGameWindow.Run(); | ||||
|  | ||||
| static ClientConfiguration GetOrCreateConfiguration(ISerializer serializer, ILogger logger, string settingsPath) | ||||
| { | ||||
|     ClientConfiguration clientConfiguration; | ||||
|  | ||||
|     try | ||||
|     { | ||||
|         clientConfiguration = serializer.Deserialize<ClientConfiguration>(File.ReadAllText(settingsPath)); | ||||
|         logger.Log(clientConfiguration, $"Configuration is successfully read"); | ||||
|     } | ||||
|     catch (FileNotFoundException) | ||||
|     { | ||||
|         clientConfiguration = new(); | ||||
|         logger.Log(clientConfiguration, $"Configuration does not exist"); | ||||
|         File.WriteAllText(settingsPath, serializer.Serialize(clientConfiguration)); | ||||
|     } | ||||
|     catch (Exception exception) | ||||
|     { | ||||
|         clientConfiguration = new(); | ||||
|         logger.LogError(clientConfiguration, $"Error loading configuration"); | ||||
|         logger.LogException(clientConfiguration, exception); | ||||
|         File.WriteAllText(settingsPath, serializer.Serialize(clientConfiguration)); | ||||
|     } | ||||
|  | ||||
|     logger.Log(clientConfiguration, $"Creating new configuration file at {settingsPath}"); | ||||
|     return clientConfiguration; | ||||
| } | ||||
| @@ -1,131 +0,0 @@ | ||||
| <?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||||
| <!-- Created with Inkscape (http://www.inkscape.org/) --> | ||||
|  | ||||
| <svg | ||||
|    width="100mm" | ||||
|    height="100mm" | ||||
|    viewBox="0 0 100 100" | ||||
|    version="1.1" | ||||
|    id="svg5" | ||||
|    inkscape:version="1.2.2 (b0a8486541, 2022-12-01)" | ||||
|    sodipodi:docname="icon.svg" | ||||
|    inkscape:export-filename="Icon.png" | ||||
|    inkscape:export-xdpi="65.024002" | ||||
|    inkscape:export-ydpi="65.024002" | ||||
|    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | ||||
|    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | ||||
|    xmlns="http://www.w3.org/2000/svg" | ||||
|    xmlns:svg="http://www.w3.org/2000/svg"> | ||||
|   <sodipodi:namedview | ||||
|      id="namedview7" | ||||
|      pagecolor="#505050" | ||||
|      bordercolor="#eeeeee" | ||||
|      borderopacity="1" | ||||
|      inkscape:showpageshadow="0" | ||||
|      inkscape:pageopacity="0" | ||||
|      inkscape:pagecheckerboard="0" | ||||
|      inkscape:deskcolor="#505050" | ||||
|      inkscape:document-units="mm" | ||||
|      showgrid="false" | ||||
|      inkscape:zoom="0.76791526" | ||||
|      inkscape:cx="-14.975611" | ||||
|      inkscape:cy="272.16545" | ||||
|      inkscape:window-width="1920" | ||||
|      inkscape:window-height="1008" | ||||
|      inkscape:window-x="0" | ||||
|      inkscape:window-y="36" | ||||
|      inkscape:window-maximized="1" | ||||
|      inkscape:current-layer="layer1" /> | ||||
|   <defs | ||||
|      id="defs2"> | ||||
|     <inkscape:path-effect | ||||
|        effect="taper_stroke" | ||||
|        id="path-effect1965" | ||||
|        is_visible="true" | ||||
|        lpeversion="1" | ||||
|        stroke_width="14.57" | ||||
|        attach_start="0.99999" | ||||
|        end_offset="1e-07" | ||||
|        start_smoothing="0" | ||||
|        end_smoothing="0" | ||||
|        jointype="extrapolated" | ||||
|        start_shape="center" | ||||
|        end_shape="center" | ||||
|        miter_limit="1000.5" /> | ||||
|     <inkscape:path-effect | ||||
|        effect="join_type" | ||||
|        id="path-effect1959" | ||||
|        is_visible="true" | ||||
|        lpeversion="1" | ||||
|        linecap_type="square" | ||||
|        line_width="0.26458299" | ||||
|        linejoin_type="extrp_arc" | ||||
|        miter_limit="100" | ||||
|        attempt_force_join="true" /> | ||||
|     <inkscape:path-effect | ||||
|        effect="powerstroke" | ||||
|        id="path-effect1957" | ||||
|        is_visible="true" | ||||
|        lpeversion="1" | ||||
|        offset_points="0.2,0.1322915 | 1,0.1322915 | 1.8,0.1322915" | ||||
|        not_jump="false" | ||||
|        sort_points="true" | ||||
|        interpolator_type="Linear" | ||||
|        interpolator_beta="1" | ||||
|        start_linecap_type="zerowidth" | ||||
|        linejoin_type="miter" | ||||
|        miter_limit="11100" | ||||
|        scale_width="20" | ||||
|        end_linecap_type="butt" /> | ||||
|     <inkscape:path-effect | ||||
|        effect="fill_between_many" | ||||
|        method="bsplinespiro" | ||||
|        linkedpaths="#path1175,0,1" | ||||
|        id="path-effect1961" | ||||
|        is_visible="true" | ||||
|        lpeversion="0" | ||||
|        join="true" | ||||
|        close="true" | ||||
|        autoreverse="true" /> | ||||
|     <inkscape:path-effect | ||||
|        effect="fill_between_many" | ||||
|        method="bsplinespiro" | ||||
|        linkedpaths="#path1175,0,1" | ||||
|        id="path-effect1967" | ||||
|        is_visible="true" | ||||
|        lpeversion="0" | ||||
|        join="true" | ||||
|        close="true" | ||||
|        autoreverse="true" /> | ||||
|   </defs> | ||||
|   <g | ||||
|      inkscape:label="Layer 1" | ||||
|      inkscape:groupmode="layer" | ||||
|      id="layer1"> | ||||
|     <rect | ||||
|        style="fill:#25202c;fill-opacity:1;stroke:none;stroke-width:0.264583;stroke-linecap:square;stroke-linejoin:bevel;stroke-opacity:1;paint-order:fill markers stroke" | ||||
|        id="rect4712" | ||||
|        width="100" | ||||
|        height="100" | ||||
|        x="0" | ||||
|        y="0" | ||||
|        ry="24.342688" /> | ||||
|     <circle | ||||
|        style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.296213;stroke-linecap:square;stroke-linejoin:bevel;paint-order:fill markers stroke" | ||||
|        id="path234" | ||||
|        cx="32.183838" | ||||
|        cy="37.277283" | ||||
|        r="11.198684" /> | ||||
|     <rect | ||||
|        style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.296213;stroke-linecap:square;stroke-linejoin:bevel;paint-order:fill markers stroke" | ||||
|        id="rect1054" | ||||
|        width="19.398724" | ||||
|        height="71.576004" | ||||
|        x="59.616123" | ||||
|        y="14.211996" /> | ||||
|     <path | ||||
|        id="path1175" | ||||
|        style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:4.31583;stroke-linecap:square;stroke-linejoin:bevel;stroke-opacity:1;paint-order:fill markers stroke" | ||||
|        d="m 45.710924,37.909235 c -0.08308,1.7843 -0.506133,3.552079 -1.278577,5.16464 -1.067261,2.404981 -2.906892,4.366553 -5.129349,5.714834 l 10.696654,4.40096 -13.418115,24.765056 21.254461,-19.595787 c 5.44e-4,-4.297076 -4.96e-4,-8.593943 5.78e-4,-12.891057 z" /> | ||||
|   </g> | ||||
| </svg> | ||||
| Before Width: | Height: | Size: 4.2 KiB | 
| @@ -1,39 +0,0 @@ | ||||
| using System; | ||||
| using System.Threading.Tasks; | ||||
|  | ||||
| using Microsoft.AspNetCore.Builder; | ||||
| using Microsoft.AspNetCore.Http; | ||||
| using Microsoft.Extensions.DependencyInjection; | ||||
|  | ||||
| using Engine.Core; | ||||
| using Engine.Systems.Network; | ||||
|  | ||||
| namespace Server; | ||||
|  | ||||
| public class PongEndpoints : Behaviour, IFirstFrameUpdate | ||||
| { | ||||
|     private INetworkCommunicatorServer? server = null!; | ||||
|  | ||||
|     public PongEndpoints() | ||||
|     { | ||||
|         Task.Run(() => | ||||
|         { | ||||
|             WebApplicationBuilder builder = WebApplication.CreateBuilder(); | ||||
|  | ||||
|             builder.Services.AddHealthChecks(); | ||||
|  | ||||
|             WebApplication app = builder.Build(); | ||||
|  | ||||
|             app.MapHealthChecks("/health"); | ||||
|  | ||||
|             app.MapGet("/stats", GetStats); | ||||
|  | ||||
|             app.Run($"http://0.0.0.0:{Environment.GetEnvironmentVariable("PORT") ?? "8888"}"); | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     private IResult GetStats() => Results.Json(new { Count = server?.Connections.Count ?? 0 }); | ||||
|  | ||||
|     public void FirstActiveFrame() => server = Universe.FindRequiredBehaviour<INetworkCommunicatorServer>(); | ||||
|     protected override void OnExitedUniverse(IUniverse universe) => server = null; | ||||
| } | ||||
| @@ -1,34 +0,0 @@ | ||||
| using System; | ||||
| using System.Threading; | ||||
|  | ||||
| using Engine.Core; | ||||
| using Engine.Core.Debug; | ||||
|  | ||||
| Universe universe = new(); | ||||
|  | ||||
| FileLogger fileLogger = new($"Logs/{DateTime.UtcNow:yyyy-MM-dd_HH-mm-ss-ffffff}.log"); | ||||
| universe.InstantiateUniverseObject().SetUniverseObject("Logger").BehaviourController | ||||
|     .AddBehaviour<LoggerContainer>().Logger = ILogger.Shared = new LoggerWrapper(fileLogger, new ConsoleLogger()); | ||||
|  | ||||
| Pong.PongUniverse.ApplyPongServer(universe, int.Parse(Environment.GetEnvironmentVariable("PORT") ?? "8888")); | ||||
| Pong.PongUniverse.ApplyPongUniverse(universe); | ||||
|  | ||||
| universe.InstantiateUniverseObject().SetUniverseObject("Endpoints").BehaviourController | ||||
|     .AddBehaviour<Server.PongEndpoints>(); | ||||
|  | ||||
| DateTime lastRun = DateTime.UtcNow; | ||||
| TimeSpan interval = new(0, 0, 0, 0, 16); | ||||
| TimeSpan timeSinceStart = new(0); | ||||
|  | ||||
| universe.Initialize(); | ||||
|  | ||||
| while (true) | ||||
| { | ||||
|     if (lastRun + interval <= DateTime.UtcNow) | ||||
|     { | ||||
|         lastRun += interval; | ||||
|         timeSinceStart += interval; | ||||
|         universe.Update(new(timeSinceStart, interval)); | ||||
|     } | ||||
|     Thread.Sleep(1); | ||||
| } | ||||
| @@ -1,22 +0,0 @@ | ||||
| <Project Sdk="Microsoft.NET.Sdk.Web"> | ||||
|  | ||||
|   <PropertyGroup> | ||||
|     <OutputType>Exe</OutputType> | ||||
|     <TargetFramework>net9.0</TargetFramework> | ||||
|     <ImplicitUsings>disable</ImplicitUsings> | ||||
|     <Nullable>enable</Nullable> | ||||
|     <RootNamespace>Pong.Platforms.Server</RootNamespace> | ||||
|     <AssemblyName>Server</AssemblyName> | ||||
|   </PropertyGroup> | ||||
|  | ||||
|   <ItemGroup> | ||||
|     <ProjectReference Include="../../Shared/Shared.csproj" /> | ||||
|   </ItemGroup> | ||||
|  | ||||
|   <ItemGroup> | ||||
|     <PackageReference Include="Microsoft.AspNetCore" Version="2.3.0" /> | ||||
|     <PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks" Version="10.0.0-preview.5.25277.114" /> | ||||
|     <PackageReference Include="MonoGame.Framework.DesktopGL" Version="3.8.2.1105" /> | ||||
|   </ItemGroup> | ||||
|  | ||||
| </Project> | ||||
							
								
								
									
										176
									
								
								Pong.sln
									
									
									
									
									
								
							
							
						
						
									
										176
									
								
								Pong.sln
									
									
									
									
									
								
							| @@ -7,171 +7,41 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Engine", "Engine", "{F7F626 | ||||
| EndProject | ||||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Engine.Core", "Engine\Engine.Core\Engine.Core.csproj", "{990CA10C-1EBB-4395-A43A-456B7029D8C9}" | ||||
| EndProject | ||||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Game", "Game\Game.csproj", "{500E1B05-39D7-4232-8051-E7351D745306}" | ||||
| EndProject | ||||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Engine.Input", "Engine\Engine.Input\Engine.Input.csproj", "{7EED4EC3-79D5-4C6C-A54D-1B396213C0E4}" | ||||
| EndProject | ||||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Engine.Physics2D", "Engine\Engine.Physics2D\Engine.Physics2D.csproj", "{0D97F83C-B043-48B1-B155-7354C4E84FC0}" | ||||
| EndProject | ||||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Engine", "Engine\Engine\Engine.csproj", "{2F6B1E26-1217-4EFD-874C-05ADEE4C7969}" | ||||
| EndProject | ||||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Shared", "Shared\Shared.csproj", "{590E392E-9FB3-49FA-B4DA-6C8F7126FFE5}" | ||||
| EndProject | ||||
| Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Platforms", "Platforms", "{FECFFD54-338F-4060-9161-1E5770D1DC33}" | ||||
| EndProject | ||||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Desktop", "Platforms\Desktop\Desktop.csproj", "{2B627F66-5A61-4F69-B479-62EEAB603D01}" | ||||
| EndProject | ||||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Engine.Systems", "Engine\Engine.Systems\Engine.Systems.csproj", "{8863A1BA-2E83-419F-BACB-D4A4156EC71C}" | ||||
| EndProject | ||||
| Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Engine.Integration", "Engine.Integration", "{9059393F-4073-9273-0EEC-2B1BA61B620B}" | ||||
| EndProject | ||||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Engine.Integration.MonoGame", "Engine\Engine.Integration\Engine.Integration.MonoGame\Engine.Integration.MonoGame.csproj", "{7CC31BC4-38EE-40F4-BBBA-9FC2F4CF6283}" | ||||
| EndProject | ||||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Server", "Platforms\Server\Server.csproj", "{A15263DB-DF65-4A07-8CA1-33A2919501A0}" | ||||
| EndProject | ||||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Engine.Integration.Yaml", "Engine\Engine.Integration\Engine.Integration.Yaml\Engine.Integration.Yaml.csproj", "{79F870AB-249E-4CA0-9DF0-F265514581DF}" | ||||
| EndProject | ||||
| Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Engine.Integration.LiteNetLib", "Engine\Engine.Integration\Engine.Integration.LiteNetLib\Engine.Integration.LiteNetLib.csproj", "{7AA22306-772F-45F4-8F30-97EBD1FC124D}" | ||||
| EndProject | ||||
| Global | ||||
| 	GlobalSection(SolutionConfigurationPlatforms) = preSolution | ||||
| 		Debug|Any CPU = Debug|Any CPU | ||||
| 		Debug|x64 = Debug|x64 | ||||
| 		Debug|x86 = Debug|x86 | ||||
| 		Release|Any CPU = Release|Any CPU | ||||
| 		Release|x64 = Release|x64 | ||||
| 		Release|x86 = Release|x86 | ||||
| 	EndGlobalSection | ||||
| 	GlobalSection(ProjectConfigurationPlatforms) = postSolution | ||||
| 		{990CA10C-1EBB-4395-A43A-456B7029D8C9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||||
| 		{990CA10C-1EBB-4395-A43A-456B7029D8C9}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||||
| 		{990CA10C-1EBB-4395-A43A-456B7029D8C9}.Debug|x64.ActiveCfg = Debug|Any CPU | ||||
| 		{990CA10C-1EBB-4395-A43A-456B7029D8C9}.Debug|x64.Build.0 = Debug|Any CPU | ||||
| 		{990CA10C-1EBB-4395-A43A-456B7029D8C9}.Debug|x86.ActiveCfg = Debug|Any CPU | ||||
| 		{990CA10C-1EBB-4395-A43A-456B7029D8C9}.Debug|x86.Build.0 = Debug|Any CPU | ||||
| 		{990CA10C-1EBB-4395-A43A-456B7029D8C9}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||||
| 		{990CA10C-1EBB-4395-A43A-456B7029D8C9}.Release|Any CPU.Build.0 = Release|Any CPU | ||||
| 		{990CA10C-1EBB-4395-A43A-456B7029D8C9}.Release|x64.ActiveCfg = Release|Any CPU | ||||
| 		{990CA10C-1EBB-4395-A43A-456B7029D8C9}.Release|x64.Build.0 = Release|Any CPU | ||||
| 		{990CA10C-1EBB-4395-A43A-456B7029D8C9}.Release|x86.ActiveCfg = Release|Any CPU | ||||
| 		{990CA10C-1EBB-4395-A43A-456B7029D8C9}.Release|x86.Build.0 = Release|Any CPU | ||||
| 		{0D97F83C-B043-48B1-B155-7354C4E84FC0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||||
| 		{0D97F83C-B043-48B1-B155-7354C4E84FC0}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||||
| 		{0D97F83C-B043-48B1-B155-7354C4E84FC0}.Debug|x64.ActiveCfg = Debug|Any CPU | ||||
| 		{0D97F83C-B043-48B1-B155-7354C4E84FC0}.Debug|x64.Build.0 = Debug|Any CPU | ||||
| 		{0D97F83C-B043-48B1-B155-7354C4E84FC0}.Debug|x86.ActiveCfg = Debug|Any CPU | ||||
| 		{0D97F83C-B043-48B1-B155-7354C4E84FC0}.Debug|x86.Build.0 = Debug|Any CPU | ||||
| 		{0D97F83C-B043-48B1-B155-7354C4E84FC0}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||||
| 		{0D97F83C-B043-48B1-B155-7354C4E84FC0}.Release|Any CPU.Build.0 = Release|Any CPU | ||||
| 		{0D97F83C-B043-48B1-B155-7354C4E84FC0}.Release|x64.ActiveCfg = Release|Any CPU | ||||
| 		{0D97F83C-B043-48B1-B155-7354C4E84FC0}.Release|x64.Build.0 = Release|Any CPU | ||||
| 		{0D97F83C-B043-48B1-B155-7354C4E84FC0}.Release|x86.ActiveCfg = Release|Any CPU | ||||
| 		{0D97F83C-B043-48B1-B155-7354C4E84FC0}.Release|x86.Build.0 = Release|Any CPU | ||||
| 		{2F6B1E26-1217-4EFD-874C-05ADEE4C7969}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||||
| 		{2F6B1E26-1217-4EFD-874C-05ADEE4C7969}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||||
| 		{2F6B1E26-1217-4EFD-874C-05ADEE4C7969}.Debug|x64.ActiveCfg = Debug|Any CPU | ||||
| 		{2F6B1E26-1217-4EFD-874C-05ADEE4C7969}.Debug|x64.Build.0 = Debug|Any CPU | ||||
| 		{2F6B1E26-1217-4EFD-874C-05ADEE4C7969}.Debug|x86.ActiveCfg = Debug|Any CPU | ||||
| 		{2F6B1E26-1217-4EFD-874C-05ADEE4C7969}.Debug|x86.Build.0 = Debug|Any CPU | ||||
| 		{2F6B1E26-1217-4EFD-874C-05ADEE4C7969}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||||
| 		{2F6B1E26-1217-4EFD-874C-05ADEE4C7969}.Release|Any CPU.Build.0 = Release|Any CPU | ||||
| 		{2F6B1E26-1217-4EFD-874C-05ADEE4C7969}.Release|x64.ActiveCfg = Release|Any CPU | ||||
| 		{2F6B1E26-1217-4EFD-874C-05ADEE4C7969}.Release|x64.Build.0 = Release|Any CPU | ||||
| 		{2F6B1E26-1217-4EFD-874C-05ADEE4C7969}.Release|x86.ActiveCfg = Release|Any CPU | ||||
| 		{2F6B1E26-1217-4EFD-874C-05ADEE4C7969}.Release|x86.Build.0 = Release|Any CPU | ||||
| 		{590E392E-9FB3-49FA-B4DA-6C8F7126FFE5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||||
| 		{590E392E-9FB3-49FA-B4DA-6C8F7126FFE5}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||||
| 		{590E392E-9FB3-49FA-B4DA-6C8F7126FFE5}.Debug|x64.ActiveCfg = Debug|Any CPU | ||||
| 		{590E392E-9FB3-49FA-B4DA-6C8F7126FFE5}.Debug|x64.Build.0 = Debug|Any CPU | ||||
| 		{590E392E-9FB3-49FA-B4DA-6C8F7126FFE5}.Debug|x86.ActiveCfg = Debug|Any CPU | ||||
| 		{590E392E-9FB3-49FA-B4DA-6C8F7126FFE5}.Debug|x86.Build.0 = Debug|Any CPU | ||||
| 		{590E392E-9FB3-49FA-B4DA-6C8F7126FFE5}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||||
| 		{590E392E-9FB3-49FA-B4DA-6C8F7126FFE5}.Release|Any CPU.Build.0 = Release|Any CPU | ||||
| 		{590E392E-9FB3-49FA-B4DA-6C8F7126FFE5}.Release|x64.ActiveCfg = Release|Any CPU | ||||
| 		{590E392E-9FB3-49FA-B4DA-6C8F7126FFE5}.Release|x64.Build.0 = Release|Any CPU | ||||
| 		{590E392E-9FB3-49FA-B4DA-6C8F7126FFE5}.Release|x86.ActiveCfg = Release|Any CPU | ||||
| 		{590E392E-9FB3-49FA-B4DA-6C8F7126FFE5}.Release|x86.Build.0 = Release|Any CPU | ||||
| 		{2B627F66-5A61-4F69-B479-62EEAB603D01}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||||
| 		{2B627F66-5A61-4F69-B479-62EEAB603D01}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||||
| 		{2B627F66-5A61-4F69-B479-62EEAB603D01}.Debug|x64.ActiveCfg = Debug|Any CPU | ||||
| 		{2B627F66-5A61-4F69-B479-62EEAB603D01}.Debug|x64.Build.0 = Debug|Any CPU | ||||
| 		{2B627F66-5A61-4F69-B479-62EEAB603D01}.Debug|x86.ActiveCfg = Debug|Any CPU | ||||
| 		{2B627F66-5A61-4F69-B479-62EEAB603D01}.Debug|x86.Build.0 = Debug|Any CPU | ||||
| 		{2B627F66-5A61-4F69-B479-62EEAB603D01}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||||
| 		{2B627F66-5A61-4F69-B479-62EEAB603D01}.Release|Any CPU.Build.0 = Release|Any CPU | ||||
| 		{2B627F66-5A61-4F69-B479-62EEAB603D01}.Release|x64.ActiveCfg = Release|Any CPU | ||||
| 		{2B627F66-5A61-4F69-B479-62EEAB603D01}.Release|x64.Build.0 = Release|Any CPU | ||||
| 		{2B627F66-5A61-4F69-B479-62EEAB603D01}.Release|x86.ActiveCfg = Release|Any CPU | ||||
| 		{2B627F66-5A61-4F69-B479-62EEAB603D01}.Release|x86.Build.0 = Release|Any CPU | ||||
| 		{8863A1BA-2E83-419F-BACB-D4A4156EC71C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||||
| 		{8863A1BA-2E83-419F-BACB-D4A4156EC71C}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||||
| 		{8863A1BA-2E83-419F-BACB-D4A4156EC71C}.Debug|x64.ActiveCfg = Debug|Any CPU | ||||
| 		{8863A1BA-2E83-419F-BACB-D4A4156EC71C}.Debug|x64.Build.0 = Debug|Any CPU | ||||
| 		{8863A1BA-2E83-419F-BACB-D4A4156EC71C}.Debug|x86.ActiveCfg = Debug|Any CPU | ||||
| 		{8863A1BA-2E83-419F-BACB-D4A4156EC71C}.Debug|x86.Build.0 = Debug|Any CPU | ||||
| 		{8863A1BA-2E83-419F-BACB-D4A4156EC71C}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||||
| 		{8863A1BA-2E83-419F-BACB-D4A4156EC71C}.Release|Any CPU.Build.0 = Release|Any CPU | ||||
| 		{8863A1BA-2E83-419F-BACB-D4A4156EC71C}.Release|x64.ActiveCfg = Release|Any CPU | ||||
| 		{8863A1BA-2E83-419F-BACB-D4A4156EC71C}.Release|x64.Build.0 = Release|Any CPU | ||||
| 		{8863A1BA-2E83-419F-BACB-D4A4156EC71C}.Release|x86.ActiveCfg = Release|Any CPU | ||||
| 		{8863A1BA-2E83-419F-BACB-D4A4156EC71C}.Release|x86.Build.0 = Release|Any CPU | ||||
| 		{7CC31BC4-38EE-40F4-BBBA-9FC2F4CF6283}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||||
| 		{7CC31BC4-38EE-40F4-BBBA-9FC2F4CF6283}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||||
| 		{7CC31BC4-38EE-40F4-BBBA-9FC2F4CF6283}.Debug|x64.ActiveCfg = Debug|Any CPU | ||||
| 		{7CC31BC4-38EE-40F4-BBBA-9FC2F4CF6283}.Debug|x64.Build.0 = Debug|Any CPU | ||||
| 		{7CC31BC4-38EE-40F4-BBBA-9FC2F4CF6283}.Debug|x86.ActiveCfg = Debug|Any CPU | ||||
| 		{7CC31BC4-38EE-40F4-BBBA-9FC2F4CF6283}.Debug|x86.Build.0 = Debug|Any CPU | ||||
| 		{7CC31BC4-38EE-40F4-BBBA-9FC2F4CF6283}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||||
| 		{7CC31BC4-38EE-40F4-BBBA-9FC2F4CF6283}.Release|Any CPU.Build.0 = Release|Any CPU | ||||
| 		{7CC31BC4-38EE-40F4-BBBA-9FC2F4CF6283}.Release|x64.ActiveCfg = Release|Any CPU | ||||
| 		{7CC31BC4-38EE-40F4-BBBA-9FC2F4CF6283}.Release|x64.Build.0 = Release|Any CPU | ||||
| 		{7CC31BC4-38EE-40F4-BBBA-9FC2F4CF6283}.Release|x86.ActiveCfg = Release|Any CPU | ||||
| 		{7CC31BC4-38EE-40F4-BBBA-9FC2F4CF6283}.Release|x86.Build.0 = Release|Any CPU | ||||
| 		{A15263DB-DF65-4A07-8CA1-33A2919501A0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||||
| 		{A15263DB-DF65-4A07-8CA1-33A2919501A0}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||||
| 		{A15263DB-DF65-4A07-8CA1-33A2919501A0}.Debug|x64.ActiveCfg = Debug|Any CPU | ||||
| 		{A15263DB-DF65-4A07-8CA1-33A2919501A0}.Debug|x64.Build.0 = Debug|Any CPU | ||||
| 		{A15263DB-DF65-4A07-8CA1-33A2919501A0}.Debug|x86.ActiveCfg = Debug|Any CPU | ||||
| 		{A15263DB-DF65-4A07-8CA1-33A2919501A0}.Debug|x86.Build.0 = Debug|Any CPU | ||||
| 		{A15263DB-DF65-4A07-8CA1-33A2919501A0}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||||
| 		{A15263DB-DF65-4A07-8CA1-33A2919501A0}.Release|Any CPU.Build.0 = Release|Any CPU | ||||
| 		{A15263DB-DF65-4A07-8CA1-33A2919501A0}.Release|x64.ActiveCfg = Release|Any CPU | ||||
| 		{A15263DB-DF65-4A07-8CA1-33A2919501A0}.Release|x64.Build.0 = Release|Any CPU | ||||
| 		{A15263DB-DF65-4A07-8CA1-33A2919501A0}.Release|x86.ActiveCfg = Release|Any CPU | ||||
| 		{A15263DB-DF65-4A07-8CA1-33A2919501A0}.Release|x86.Build.0 = Release|Any CPU | ||||
| 		{79F870AB-249E-4CA0-9DF0-F265514581DF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||||
| 		{79F870AB-249E-4CA0-9DF0-F265514581DF}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||||
| 		{79F870AB-249E-4CA0-9DF0-F265514581DF}.Debug|x64.ActiveCfg = Debug|Any CPU | ||||
| 		{79F870AB-249E-4CA0-9DF0-F265514581DF}.Debug|x64.Build.0 = Debug|Any CPU | ||||
| 		{79F870AB-249E-4CA0-9DF0-F265514581DF}.Debug|x86.ActiveCfg = Debug|Any CPU | ||||
| 		{79F870AB-249E-4CA0-9DF0-F265514581DF}.Debug|x86.Build.0 = Debug|Any CPU | ||||
| 		{79F870AB-249E-4CA0-9DF0-F265514581DF}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||||
| 		{79F870AB-249E-4CA0-9DF0-F265514581DF}.Release|Any CPU.Build.0 = Release|Any CPU | ||||
| 		{79F870AB-249E-4CA0-9DF0-F265514581DF}.Release|x64.ActiveCfg = Release|Any CPU | ||||
| 		{79F870AB-249E-4CA0-9DF0-F265514581DF}.Release|x64.Build.0 = Release|Any CPU | ||||
| 		{79F870AB-249E-4CA0-9DF0-F265514581DF}.Release|x86.ActiveCfg = Release|Any CPU | ||||
| 		{79F870AB-249E-4CA0-9DF0-F265514581DF}.Release|x86.Build.0 = Release|Any CPU | ||||
| 		{7AA22306-772F-45F4-8F30-97EBD1FC124D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||||
| 		{7AA22306-772F-45F4-8F30-97EBD1FC124D}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||||
| 		{7AA22306-772F-45F4-8F30-97EBD1FC124D}.Debug|x64.ActiveCfg = Debug|Any CPU | ||||
| 		{7AA22306-772F-45F4-8F30-97EBD1FC124D}.Debug|x64.Build.0 = Debug|Any CPU | ||||
| 		{7AA22306-772F-45F4-8F30-97EBD1FC124D}.Debug|x86.ActiveCfg = Debug|Any CPU | ||||
| 		{7AA22306-772F-45F4-8F30-97EBD1FC124D}.Debug|x86.Build.0 = Debug|Any CPU | ||||
| 		{7AA22306-772F-45F4-8F30-97EBD1FC124D}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||||
| 		{7AA22306-772F-45F4-8F30-97EBD1FC124D}.Release|Any CPU.Build.0 = Release|Any CPU | ||||
| 		{7AA22306-772F-45F4-8F30-97EBD1FC124D}.Release|x64.ActiveCfg = Release|Any CPU | ||||
| 		{7AA22306-772F-45F4-8F30-97EBD1FC124D}.Release|x64.Build.0 = Release|Any CPU | ||||
| 		{7AA22306-772F-45F4-8F30-97EBD1FC124D}.Release|x86.ActiveCfg = Release|Any CPU | ||||
| 		{7AA22306-772F-45F4-8F30-97EBD1FC124D}.Release|x86.Build.0 = Release|Any CPU | ||||
| 	EndGlobalSection | ||||
| 	GlobalSection(SolutionProperties) = preSolution | ||||
| 		HideSolutionNode = FALSE | ||||
| 	EndGlobalSection | ||||
| 	GlobalSection(ProjectConfigurationPlatforms) = postSolution | ||||
| 		{990CA10C-1EBB-4395-A43A-456B7029D8C9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||||
| 		{990CA10C-1EBB-4395-A43A-456B7029D8C9}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||||
| 		{990CA10C-1EBB-4395-A43A-456B7029D8C9}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||||
| 		{990CA10C-1EBB-4395-A43A-456B7029D8C9}.Release|Any CPU.Build.0 = Release|Any CPU | ||||
| 		{500E1B05-39D7-4232-8051-E7351D745306}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||||
| 		{500E1B05-39D7-4232-8051-E7351D745306}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||||
| 		{500E1B05-39D7-4232-8051-E7351D745306}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||||
| 		{500E1B05-39D7-4232-8051-E7351D745306}.Release|Any CPU.Build.0 = Release|Any CPU | ||||
| 		{7EED4EC3-79D5-4C6C-A54D-1B396213C0E4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||||
| 		{7EED4EC3-79D5-4C6C-A54D-1B396213C0E4}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||||
| 		{7EED4EC3-79D5-4C6C-A54D-1B396213C0E4}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||||
| 		{7EED4EC3-79D5-4C6C-A54D-1B396213C0E4}.Release|Any CPU.Build.0 = Release|Any CPU | ||||
| 		{0D97F83C-B043-48B1-B155-7354C4E84FC0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||||
| 		{0D97F83C-B043-48B1-B155-7354C4E84FC0}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||||
| 		{0D97F83C-B043-48B1-B155-7354C4E84FC0}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||||
| 		{0D97F83C-B043-48B1-B155-7354C4E84FC0}.Release|Any CPU.Build.0 = Release|Any CPU | ||||
| 	EndGlobalSection | ||||
| 	GlobalSection(NestedProjects) = preSolution | ||||
| 		{990CA10C-1EBB-4395-A43A-456B7029D8C9} = {F7F62670-237A-4C93-A30E-CE661C6FC401} | ||||
| 		{7EED4EC3-79D5-4C6C-A54D-1B396213C0E4} = {F7F62670-237A-4C93-A30E-CE661C6FC401} | ||||
| 		{0D97F83C-B043-48B1-B155-7354C4E84FC0} = {F7F62670-237A-4C93-A30E-CE661C6FC401} | ||||
| 		{2F6B1E26-1217-4EFD-874C-05ADEE4C7969} = {F7F62670-237A-4C93-A30E-CE661C6FC401} | ||||
| 		{2B627F66-5A61-4F69-B479-62EEAB603D01} = {FECFFD54-338F-4060-9161-1E5770D1DC33} | ||||
| 		{8863A1BA-2E83-419F-BACB-D4A4156EC71C} = {F7F62670-237A-4C93-A30E-CE661C6FC401} | ||||
| 		{9059393F-4073-9273-0EEC-2B1BA61B620B} = {F7F62670-237A-4C93-A30E-CE661C6FC401} | ||||
| 		{7CC31BC4-38EE-40F4-BBBA-9FC2F4CF6283} = {9059393F-4073-9273-0EEC-2B1BA61B620B} | ||||
| 		{A15263DB-DF65-4A07-8CA1-33A2919501A0} = {FECFFD54-338F-4060-9161-1E5770D1DC33} | ||||
| 		{7AA22306-772F-45F4-8F30-97EBD1FC124D} = {9059393F-4073-9273-0EEC-2B1BA61B620B} | ||||
| 	EndGlobalSection | ||||
| EndGlobal | ||||
|   | ||||
| @@ -1,36 +0,0 @@ | ||||
| { | ||||
|   "version": 1, | ||||
|   "isRoot": true, | ||||
|   "tools": { | ||||
|     "dotnet-mgcb": { | ||||
|       "version": "3.8.2.1105", | ||||
|       "commands": [ | ||||
|         "mgcb" | ||||
|       ] | ||||
|     }, | ||||
|     "dotnet-mgcb-editor": { | ||||
|       "version": "3.8.2.1105", | ||||
|       "commands": [ | ||||
|         "mgcb-editor" | ||||
|       ] | ||||
|     }, | ||||
|     "dotnet-mgcb-editor-linux": { | ||||
|       "version": "3.8.2.1105", | ||||
|       "commands": [ | ||||
|         "mgcb-editor-linux" | ||||
|       ] | ||||
|     }, | ||||
|     "dotnet-mgcb-editor-windows": { | ||||
|       "version": "3.8.2.1105", | ||||
|       "commands": [ | ||||
|         "mgcb-editor-windows" | ||||
|       ] | ||||
|     }, | ||||
|     "dotnet-mgcb-editor-mac": { | ||||
|       "version": "3.8.2.1105", | ||||
|       "commands": [ | ||||
|         "mgcb-editor-mac" | ||||
|       ] | ||||
|     } | ||||
|   } | ||||
| } | ||||
| @@ -1,110 +0,0 @@ | ||||
| using Microsoft.Xna.Framework.Audio; | ||||
| using Microsoft.Xna.Framework.Content; | ||||
|  | ||||
| using Engine.Core; | ||||
| using Engine.Integration.MonoGame; | ||||
| using Engine.Systems.Network; | ||||
| using Engine.Physics2D; | ||||
| using Engine.Systems.Tween; | ||||
|  | ||||
| namespace Pong.Behaviours; | ||||
|  | ||||
| public class Ball : Behaviour2D, IFirstFrameUpdate, ILoadContent, IPhysicsUpdate, INetworkEntity, | ||||
|     IPacketListenerClient<Ball.BallUpdatePacket>, | ||||
|     IPacketListenerClient<Ball.BallResetPacket> | ||||
| { | ||||
|     public float Speed { get; set; } = 500f; | ||||
|     public float SpeedUpMultiplier { get; set; } = .025f; | ||||
|  | ||||
|     public IRigidBody2D RigidBody { get; private set; } = null!; | ||||
|  | ||||
|     private IPhysicsEngine2D physicsEngine2D = null!; | ||||
|     private ITweenManager tweenManager = null!; | ||||
|     private INetworkCommunicatorServer? networkServer = null; | ||||
|     private ITween? networkTween = null; | ||||
|  | ||||
|     private SoundEffect? bounceSoundEffect = null; | ||||
|  | ||||
|     public void FirstActiveFrame() | ||||
|     { | ||||
|         BehaviourController.GetRequiredBehaviour<ICollider2D>().OnCollisionDetected.AddListener(OnCollisionDetected); | ||||
|         physicsEngine2D = Universe.FindRequiredBehaviour<IPhysicsEngine2D>(); | ||||
|         tweenManager = Universe.FindRequiredBehaviour<ITweenManager>(); | ||||
|         RigidBody = BehaviourController.GetRequiredBehaviour<IRigidBody2D>(); | ||||
|         networkServer = Universe.FindBehaviour<INetworkCommunicatorServer>(); | ||||
|     } | ||||
|  | ||||
|     public void LoadContent(ContentManager content) | ||||
|     { | ||||
|         bounceSoundEffect = content.Load<SoundEffect>("Audio/Bounce"); | ||||
|     } | ||||
|  | ||||
|     public void LaunchBall(Vector2D launchDirection) | ||||
|     { | ||||
|         ResetBall(); | ||||
|         RigidBody.Velocity = launchDirection * Speed; | ||||
|         networkServer?.SendToAll(new BallUpdatePacket(this)); | ||||
|     } | ||||
|  | ||||
|     public void ResetBall() | ||||
|     { | ||||
|         if (networkTween is not null) | ||||
|             tweenManager.CancelTween(networkTween); | ||||
|         Transform.Position = Vector2D.Zero; | ||||
|         RigidBody.Velocity = Vector2D.Zero; | ||||
|         networkServer?.SendToAll(new BallResetPacket()); | ||||
|     } | ||||
|  | ||||
|     public void PhysicsUpdate(float delta) | ||||
|     { | ||||
|         if (RigidBody.Velocity.MagnitudeSquared <= 0.01f) | ||||
|             return; | ||||
|  | ||||
|         Vector2D direction = RigidBody.Velocity.Normalized; | ||||
|         RigidBody.Velocity += direction * delta * SpeedUpMultiplier; | ||||
|     } | ||||
|  | ||||
|     private void OnCollisionDetected(ICollider2D collider2D, CollisionDetectionInformation information) | ||||
|     { | ||||
|         if (Math.Abs(information.Normal.Dot(Vector2D.Right)) > .25) | ||||
|             RigidBody.Velocity = information.Detected.Transform.Position.FromTo(information.Detector.Transform.Position).Normalized * RigidBody.Velocity.Magnitude; | ||||
|         else | ||||
|             RigidBody.Velocity = RigidBody.Velocity.Reflect(information.Normal); | ||||
|  | ||||
|         if (information.Detected.Transform.BehaviourController.GetBehaviour<ScoreWall>() is null) | ||||
|             networkServer?.SendToAll(new BallUpdatePacket(this)); | ||||
|     } | ||||
|  | ||||
|     public Ball() { } | ||||
|     public Ball(float speed) => Speed = speed; | ||||
|  | ||||
|     void IPacketListenerClient<BallResetPacket>.OnClientPacketArrived(IConnection sender, BallResetPacket packet) => ResetBall(); | ||||
|     void IPacketListenerClient<BallUpdatePacket>.OnClientPacketArrived(IConnection sender, BallUpdatePacket packet) | ||||
|     { | ||||
|         Vector2D localToServerPosition = Transform.Position.FromTo(packet.Position); | ||||
|         if (localToServerPosition.MagnitudeSquared < 4f) | ||||
|             networkTween = Transform.TweenPositionAdditive(tweenManager, .25f, localToServerPosition); | ||||
|         else | ||||
|             Transform.Position = packet.Position; | ||||
|  | ||||
|         if (RigidBody.Velocity.MagnitudeSquared >= .01f) | ||||
|             bounceSoundEffect?.Play(); | ||||
|  | ||||
|         RigidBody.Velocity = packet.Velocity; | ||||
|         physicsEngine2D.StepIndividual(RigidBody, sender.Ping); | ||||
|     } | ||||
|  | ||||
|     private class BallResetPacket : INetworkPacket; | ||||
|     private class BallUpdatePacket : INetworkPacket | ||||
|     { | ||||
|         public Vector2D Position { get; set; } = Vector2D.Zero; | ||||
|         public Vector2D Velocity { get; set; } = Vector2D.Zero; | ||||
|  | ||||
|         public BallUpdatePacket() { } | ||||
|         public BallUpdatePacket(Ball ballBehaviour) | ||||
|         { | ||||
|             Position = ballBehaviour.Transform.Position; | ||||
|             Velocity = ballBehaviour.RigidBody.Velocity; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -1,69 +0,0 @@ | ||||
| using Microsoft.Xna.Framework.Input; | ||||
|  | ||||
| using Engine.Core; | ||||
| using Engine.Integration.MonoGame; | ||||
| using Engine.Systems.Input; | ||||
|  | ||||
| namespace Pong.Behaviours; | ||||
|  | ||||
| public class CameraController : Behaviour, IFirstFrameUpdate, IUpdate | ||||
| { | ||||
|     private MonoGameCamera2D cameraBehaviour = null!; | ||||
|     private IButtonInputs<Keys> buttonInputs = null!; | ||||
|  | ||||
|     private float defaultZoomLevel = 1f; | ||||
|  | ||||
|     public void FirstActiveFrame() | ||||
|     { | ||||
|         cameraBehaviour = BehaviourController.GetRequiredBehaviour<MonoGameCamera2D>(); | ||||
|         buttonInputs = Universe.FindRequiredBehaviour<IButtonInputs<Keys>>(); | ||||
|  | ||||
|         buttonInputs.RegisterOnPress(Keys.F, SwitchToFullScreen); | ||||
|         buttonInputs.RegisterOnPress(Keys.R, ResetCamera); | ||||
|     } | ||||
|  | ||||
|     public void Update() | ||||
|     { | ||||
|         if (buttonInputs.IsPressed(Keys.U)) | ||||
|             cameraBehaviour.Zoom += Universe.Time.DeltaTime * 5f; | ||||
|         if (buttonInputs.IsPressed(Keys.J)) | ||||
|             cameraBehaviour.Zoom -= Universe.Time.DeltaTime * 5f; | ||||
|  | ||||
|  | ||||
|         if (buttonInputs.IsPressed(Keys.NumPad8)) cameraBehaviour.Transform.LocalPosition += Vector2D.Up * Universe.Time.DeltaTime * 500f; | ||||
|         if (buttonInputs.IsPressed(Keys.NumPad2)) cameraBehaviour.Transform.LocalPosition -= Vector2D.Up * Universe.Time.DeltaTime * 500f; | ||||
|         if (buttonInputs.IsPressed(Keys.NumPad6)) cameraBehaviour.Transform.LocalPosition += Vector2D.Right * Universe.Time.DeltaTime * 500f; | ||||
|         if (buttonInputs.IsPressed(Keys.NumPad4)) cameraBehaviour.Transform.LocalPosition -= Vector2D.Right * Universe.Time.DeltaTime * 500f; | ||||
|  | ||||
|  | ||||
|         if (buttonInputs.IsPressed(Keys.Q)) | ||||
|             cameraBehaviour.Transform.Rotation += Universe.Time.DeltaTime * 45f; | ||||
|         if (buttonInputs.IsPressed(Keys.E)) | ||||
|             cameraBehaviour.Transform.Rotation -= Universe.Time.DeltaTime * 45f; | ||||
|     } | ||||
|  | ||||
|     private void SwitchToFullScreen(IButtonInputs<Keys> sender, IButtonInputs<Keys>.ButtonCallbackArguments args) | ||||
|     { | ||||
|         if (cameraBehaviour.Graphics.IsFullScreen) | ||||
|             return; | ||||
|  | ||||
|         cameraBehaviour.Graphics.PreferMultiSampling = false; | ||||
|         cameraBehaviour.Graphics.PreferredBackBufferWidth = cameraBehaviour.Graphics.GraphicsDevice.Adapter.CurrentDisplayMode.Width; | ||||
|         cameraBehaviour.Graphics.PreferredBackBufferHeight = cameraBehaviour.Graphics.GraphicsDevice.Adapter.CurrentDisplayMode.Height; | ||||
|         cameraBehaviour.Graphics.IsFullScreen = true; | ||||
|         cameraBehaviour.Graphics.ApplyChanges(); | ||||
|  | ||||
|         float previousScreenSize = Math.Sqrt(Math.Sqr(cameraBehaviour.Viewport.Width) + Math.Sqr(cameraBehaviour.Viewport.Height)); | ||||
|         float currentScreenSize = Math.Sqrt(Math.Sqr(cameraBehaviour.Graphics.GraphicsDevice.Viewport.Width) + Math.Sqr(cameraBehaviour.Graphics.GraphicsDevice.Viewport.Height)); | ||||
|         defaultZoomLevel /= previousScreenSize / currentScreenSize; | ||||
|         cameraBehaviour.Zoom /= previousScreenSize / currentScreenSize; | ||||
|         cameraBehaviour.Viewport = cameraBehaviour.Graphics.GraphicsDevice.Viewport; | ||||
|     } | ||||
|  | ||||
|     private void ResetCamera(IButtonInputs<Keys> sender, IButtonInputs<Keys>.ButtonCallbackArguments args) | ||||
|     { | ||||
|         cameraBehaviour.Zoom = defaultZoomLevel; | ||||
|         cameraBehaviour.Transform.LocalPosition = Vector2D.Zero; | ||||
|         cameraBehaviour.Transform.LocalRotation = 0f; | ||||
|     } | ||||
| } | ||||
| @@ -1,29 +0,0 @@ | ||||
| using Engine.Core; | ||||
| using Engine.Integration.MonoGame; | ||||
|  | ||||
| namespace Pong.Behaviours; | ||||
|  | ||||
| public class DrawableColliderCircle : Engine.Physics2D.Collider2DCircle, IDrawableTriangle | ||||
| { | ||||
|     private const float CIRCLE_SEGMENT_COUNT = 32f; | ||||
|  | ||||
|     public ColorRGBA Color { get; set; } = new ColorRGBA(255, 255, 255); | ||||
|  | ||||
|     public void Draw(ITriangleBatch triangleBatch) | ||||
|     { | ||||
|         Recalculate(); | ||||
|  | ||||
|         for (int i = 0; i < CIRCLE_SEGMENT_COUNT; i++) | ||||
|         { | ||||
|             float iPi1 = i / CIRCLE_SEGMENT_COUNT * 2f * Math.Pi; | ||||
|             float iPi2 = (i + 1f).Mod(CIRCLE_SEGMENT_COUNT) / CIRCLE_SEGMENT_COUNT * 2f * Math.Pi; | ||||
|  | ||||
|             Vector2D firstVertex = new Vector2D(Math.Sin(iPi1), Math.Cos(iPi1)) * CircleWorld.Radius; | ||||
|             Vector2D secondVertex = new Vector2D(Math.Sin(iPi2), Math.Cos(iPi2)) * CircleWorld.Radius; | ||||
|             triangleBatch.Draw(new(CircleWorld.Center, CircleWorld.Center + firstVertex, CircleWorld.Center + secondVertex), Color); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public DrawableColliderCircle(Circle circle) : base(circle) { } | ||||
|     public DrawableColliderCircle(Circle circle, ColorRGBA color) : base(circle) { Color = color; } | ||||
| } | ||||
| @@ -1,26 +0,0 @@ | ||||
| using System.Collections.Generic; | ||||
|  | ||||
| using Engine.Core; | ||||
| using Engine.Integration.MonoGame; | ||||
|  | ||||
| namespace Pong.Behaviours; | ||||
|  | ||||
| public class DrawableColliderShape : Engine.Physics2D.Collider2DShape, IDrawableTriangle | ||||
| { | ||||
|     private readonly IList<Triangle> triangles = []; | ||||
|  | ||||
|     public ColorRGBA Color { get; set; } = new ColorRGBA(255, 255, 255); | ||||
|  | ||||
|     public void Draw(ITriangleBatch triangleBatch) | ||||
|     { | ||||
|         Recalculate(); | ||||
|  | ||||
|         ShapeWorld.ToTrianglesConvex(triangles); | ||||
|  | ||||
|         foreach (Triangle triangle in triangles) | ||||
|             triangleBatch.Draw(triangle, Color); | ||||
|     } | ||||
|  | ||||
|     public DrawableColliderShape(Shape2D shape) : base(shape) { } | ||||
|     public DrawableColliderShape(Shape2D shape, ColorRGBA color) : base(shape) { Color = color; } | ||||
| } | ||||
| @@ -1,31 +0,0 @@ | ||||
| using Microsoft.Xna.Framework.Content; | ||||
| using Microsoft.Xna.Framework.Graphics; | ||||
|  | ||||
| using Engine.Core; | ||||
| using Engine.Integration.MonoGame; | ||||
|  | ||||
| namespace Pong.Behaviours; | ||||
|  | ||||
| public class Label : Behaviour2D, IDrawableSprite, ILoadContent | ||||
| { | ||||
|     public SpriteFont? Font { get; set; } = null; | ||||
|     public ColorRGBA Color { get; set; } = new ColorRGBA(255, 255, 255, 255); | ||||
|     public int Size { get; set; } = 16; | ||||
|     public string Text { get; set; } = string.Empty; | ||||
|  | ||||
|     public void Draw(ISpriteBatch spriteBatch) | ||||
|     { | ||||
|         if (Font is null) | ||||
|             return; | ||||
|  | ||||
|         spriteBatch.DrawString(Font, Text, Transform.Position, Color.ToPreMultipliedColor(), Transform.Rotation, Vector2D.One * .5f, Transform.Scale.Magnitude, SpriteEffects.None, 0f); | ||||
|     } | ||||
|  | ||||
|     public void LoadContent(ContentManager content) | ||||
|     { | ||||
|         Font ??= content.Load<SpriteFont>("UbuntuMono"); | ||||
|     } | ||||
|  | ||||
|     public Label() { } | ||||
|     public Label(SpriteFont font) => Font = font; | ||||
| } | ||||
| @@ -1,117 +0,0 @@ | ||||
| using System; | ||||
|  | ||||
| using Microsoft.Xna.Framework.Input; | ||||
|  | ||||
| using Engine.Core; | ||||
| using Engine.Systems.Network; | ||||
| using Engine.Physics2D; | ||||
| using Engine.Systems.Input; | ||||
| using Engine.Systems.Tween; | ||||
|  | ||||
| namespace Pong.Behaviours; | ||||
|  | ||||
| public class Paddle(Keys Up, Keys Down, float High, float Low, float Speed) : Behaviour2D, | ||||
|     IFirstFrameUpdate, IPhysicsIteration, IPostPhysicsUpdate, | ||||
|     IPacketListenerServer<Paddle.PaddleKeyStatePacket>, IPacketListenerClient<Paddle.PaddleKeyStatePacket> | ||||
| { | ||||
|     private Keys Up { get; } = Up; | ||||
|     private Keys Down { get; } = Down; | ||||
|     public float High { get; } = High; | ||||
|     public float Low { get; } = Low; | ||||
|     public float Speed { get; set; } = Speed; | ||||
|  | ||||
|     private bool isUpPressed = false; | ||||
|     private bool isDownPressed = false; | ||||
|  | ||||
|     private IButtonInputs<Keys>? inputs = null; | ||||
|     private INetworkCommunicatorClient? networkClient = null!; | ||||
|     private INetworkCommunicatorServer? networkServer = null; | ||||
|     private IRigidBody2D rigidBody = null!; | ||||
|     private IPhysicsEngine2D physicsEngine2D = null!; | ||||
|  | ||||
|     private ITween? networkTween = null; | ||||
|     private ITweenManager tweenManager = null!; | ||||
|  | ||||
|     public void PhysicsIterate(float delta) | ||||
|     { | ||||
|         if (isUpPressed) | ||||
|             rigidBody.Transform.Position += Vector2D.Up * Speed * delta; | ||||
|         else if (isDownPressed) | ||||
|             rigidBody.Transform.Position -= Vector2D.Up * Speed * delta; | ||||
|     } | ||||
|  | ||||
|     public void PostPhysicsUpdate(float delta) | ||||
|     { | ||||
|         Transform.Position = new Vector2D(Transform.Position.X, MathF.Max(MathF.Min(Transform.Position.Y, High), Low)); | ||||
|     } | ||||
|  | ||||
|     public void FirstActiveFrame() | ||||
|     { | ||||
|         physicsEngine2D = Universe.FindRequiredBehaviour<IPhysicsEngine2D>(); | ||||
|         inputs = Universe.FindBehaviour<IButtonInputs<Keys>>(); | ||||
|         networkClient = Universe.FindBehaviour<INetworkCommunicatorClient>(); | ||||
|         networkServer = Universe.FindBehaviour<INetworkCommunicatorServer>(); | ||||
|         rigidBody = BehaviourController.GetRequiredBehaviour<IRigidBody2D>(); | ||||
|         tweenManager = Universe.FindRequiredBehaviour<ITweenManager>(); | ||||
|  | ||||
|         inputs?.RegisterOnPress(Up, OnUpPressed); | ||||
|         inputs?.RegisterOnRelease(Up, OnUpReleased); | ||||
|  | ||||
|         inputs?.RegisterOnPress(Down, OnDownPressed); | ||||
|         inputs?.RegisterOnRelease(Down, OnDownReleased); | ||||
|     } | ||||
|  | ||||
|     private void OnUpPressed(IButtonInputs<Keys> sender, IButtonInputs<Keys>.ButtonCallbackArguments args) { isUpPressed = true; networkClient?.SendToServer(new PaddleKeyStatePacket(this)); } | ||||
|     private void OnUpReleased(IButtonInputs<Keys> sender, IButtonInputs<Keys>.ButtonCallbackArguments args) { isUpPressed = false; networkClient?.SendToServer(new PaddleKeyStatePacket(this)); } | ||||
|     private void OnDownPressed(IButtonInputs<Keys> sender, IButtonInputs<Keys>.ButtonCallbackArguments args) { isDownPressed = true; networkClient?.SendToServer(new PaddleKeyStatePacket(this)); } | ||||
|     private void OnDownReleased(IButtonInputs<Keys> sender, IButtonInputs<Keys>.ButtonCallbackArguments args) { isDownPressed = false; networkClient?.SendToServer(new PaddleKeyStatePacket(this)); } | ||||
|  | ||||
|     public void OnServerPacketArrived(IConnection sender, PaddleKeyStatePacket packet) | ||||
|     { | ||||
|         physicsEngine2D.StepIndividual(rigidBody, -sender.Ping.Min(.05f)); | ||||
|  | ||||
|         isUpPressed = packet.IsUpPressed; | ||||
|         isDownPressed = packet.IsDownPressed; | ||||
|  | ||||
|         physicsEngine2D.StepIndividual(rigidBody, sender.Ping.Min(.05f)); | ||||
|         networkServer?.SendToAll(new PaddleKeyStatePacket(this)); | ||||
|     } | ||||
|  | ||||
|     public void OnClientPacketArrived(IConnection sender, PaddleKeyStatePacket packet) | ||||
|     { | ||||
|         if (packet.IsDownPressed || packet.IsUpPressed) // Check if the server paddle is moving | ||||
|             if (isDownPressed == packet.IsDownPressed && isUpPressed == packet.IsUpPressed) // Check if we are the ones giving the inputs | ||||
|                 return; | ||||
|  | ||||
|         physicsEngine2D.StepIndividual(rigidBody, -sender.Ping); | ||||
|  | ||||
|         isUpPressed = packet.IsUpPressed; | ||||
|         isDownPressed = packet.IsDownPressed; | ||||
|  | ||||
|         physicsEngine2D.StepIndividual(rigidBody, sender.Ping); | ||||
|  | ||||
|         Vector2D localToServerPosition = Transform.Position.FromTo(packet.Position); | ||||
|         networkTween = Transform.TweenPositionAdditive(tweenManager, .1f, localToServerPosition); | ||||
|     } | ||||
|  | ||||
|     public class PaddleKeyStatePacket : IEntityNetworkPacket | ||||
|     { | ||||
|         public string EntityId { get; set; } = default!; | ||||
|         public Vector2D Position { get; set; } = default!; | ||||
|         public bool IsUpPressed { get; set; } = default!; | ||||
|         public bool IsDownPressed { get; set; } = default!; | ||||
|  | ||||
|         public PaddleKeyStatePacket Set(Paddle paddleBehaviour) | ||||
|         { | ||||
|             EntityId = paddleBehaviour.Id; | ||||
|             Position = paddleBehaviour.Transform.Position; | ||||
|             IsUpPressed = paddleBehaviour.isUpPressed; | ||||
|             IsDownPressed = paddleBehaviour.isDownPressed; | ||||
|  | ||||
|             return this; | ||||
|         } | ||||
|  | ||||
|         public PaddleKeyStatePacket() { } | ||||
|         public PaddleKeyStatePacket(Paddle paddleBehaviour) => Set(paddleBehaviour); | ||||
|     } | ||||
| } | ||||
| @@ -1,107 +0,0 @@ | ||||
| using Microsoft.Xna.Framework.Audio; | ||||
| using Microsoft.Xna.Framework.Content; | ||||
| using Microsoft.Xna.Framework.Input; | ||||
|  | ||||
| using Engine.Core; | ||||
| using Engine.Core.Debug; | ||||
| using Engine.Integration.MonoGame; | ||||
| using Engine.Systems.Network; | ||||
| using Engine.Systems.Input; | ||||
| using Engine.Systems.Time; | ||||
| using Engine.Systems.Tween; | ||||
|  | ||||
| namespace Pong.Behaviours; | ||||
|  | ||||
| public class PongGameStarter : Behaviour, INetworkEntity, IFirstFrameUpdate, ILoadContent, | ||||
|     IPacketListenerServer<PongGameStarter.RequestStartPacket>, | ||||
|     IPacketListenerClient<PongGameStarter.RequestStartPacket> | ||||
| { | ||||
|     private const float START_COUNTDOWN = 3f; | ||||
|  | ||||
|     private INetworkCommunicatorServer? networkServer = null; | ||||
|     private INetworkCommunicatorClient? networkClient = null; | ||||
|     private ITweenManager? tweenManager = null; | ||||
|     private PongManager pongManager = null!; | ||||
|  | ||||
|     private ILogger? logger = null; | ||||
|  | ||||
|     private Label? label = null; | ||||
|     private TickerTimer timer = null!; | ||||
|  | ||||
|     private SoundEffectInstance? tickSoundEffect = null; | ||||
|     private SoundEffectInstance? startSoundEffect = null; | ||||
|  | ||||
|     public void FirstActiveFrame() | ||||
|     { | ||||
|         IButtonInputs<Keys>? buttonInputs = Universe.FindBehaviour<IButtonInputs<Keys>>(); | ||||
|         buttonInputs?.RegisterOnRelease(Keys.Space, (_, _1) => networkClient?.SendToServer(new RequestStartPacket())); | ||||
|  | ||||
|         networkClient = Universe.FindBehaviour<INetworkCommunicatorClient>(); | ||||
|         networkServer = Universe.FindBehaviour<INetworkCommunicatorServer>(); | ||||
|         tweenManager = Universe.FindBehaviour<ITweenManager>(); | ||||
|         pongManager = BehaviourController.GetRequiredBehaviourInParent<PongManager>(); | ||||
|         label = BehaviourController.GetRequiredBehaviour<Label>(); | ||||
|         logger = Universe.FindBehaviour<ILogger>(); | ||||
|  | ||||
|         if (!BehaviourController.TryGetBehaviour(out timer!)) | ||||
|         { | ||||
|             timer = BehaviourController.AddBehaviour<TickerTimer>(); | ||||
|             timer.OnStarted.AddListener(OnCountdownStart); | ||||
|             timer.OnTick.AddListener(DisplayCountdown); | ||||
|             timer.OnStopped.AddListener(StartPong); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public void LoadContent(ContentManager content) | ||||
|     { | ||||
|         tickSoundEffect = content.Load<SoundEffect>("Audio/TimerTick").CreateInstance(); | ||||
|         startSoundEffect = content.Load<SoundEffect>("Audio/TimerEnd").CreateInstance(); | ||||
|     } | ||||
|  | ||||
|     private void OnCountdownStart(IReadOnlyTimer sender) | ||||
|     { | ||||
|         pongManager.Reset(); | ||||
|         DisplayCountdown(timer); | ||||
|     } | ||||
|  | ||||
|     private void DisplayCountdown(ITicker sender) | ||||
|     { | ||||
|         tickSoundEffect?.Play(); | ||||
|  | ||||
|         if (label != null) | ||||
|         { | ||||
|             label.Text = $"{START_COUNTDOWN - timer.TickCounter}"; | ||||
|             label.Color = new ColorRGBA(255, 255, 255, 255); | ||||
|             if (tweenManager is not null) | ||||
|                 label.Color.TweenColor(tweenManager, 1f, new ColorRGBA(255, 255, 255, 0), (x) => label.Color = x); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private void StartPong(IReadOnlyTimer sender) | ||||
|     { | ||||
|         startSoundEffect?.Play(); | ||||
|         pongManager.Start(); | ||||
|     } | ||||
|  | ||||
|     void IPacketListenerServer<RequestStartPacket>.OnServerPacketArrived(IConnection sender, RequestStartPacket packet) | ||||
|     { | ||||
|         logger?.Log(this, $"{sender} requested start"); | ||||
|  | ||||
|         if (pongManager.IsGameInProgress) | ||||
|         { | ||||
|             logger?.Log(this, $"The game is already in progress"); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         timer.Start(START_COUNTDOWN); | ||||
|         networkServer?.SendToAll(packet); | ||||
|     } | ||||
|  | ||||
|     void IPacketListenerClient<RequestStartPacket>.OnClientPacketArrived(IConnection sender, RequestStartPacket packet) | ||||
|     { | ||||
|         logger?.Log(this, $"Server is starting the game"); | ||||
|         timer.Start(START_COUNTDOWN - sender.Ping); | ||||
|     } | ||||
|  | ||||
|     private class RequestStartPacket : INetworkPacket; | ||||
| } | ||||
| @@ -1,154 +0,0 @@ | ||||
| using System; | ||||
|  | ||||
| using Microsoft.Xna.Framework.Audio; | ||||
| using Microsoft.Xna.Framework.Content; | ||||
|  | ||||
| using Engine.Core; | ||||
| using Engine.Core.Debug; | ||||
| using Engine.Integration.MonoGame; | ||||
| using Engine.Systems.Network; | ||||
|  | ||||
| namespace Pong.Behaviours; | ||||
|  | ||||
| public class PongManager : Behaviour, INetworkEntity, IFirstFrameUpdate, ILoadContent, | ||||
|     IPacketListenerClient<PongManager.StartPacket>, | ||||
|     IPacketListenerClient<PongManager.ScorePacket> | ||||
| { | ||||
|     public Action<PongManager>? OnReset { get; set; } = null; | ||||
|     public Action<PongManager>? OnFinished { get; set; } = null; | ||||
|     public Action<PongManager>? OnScoreUpdated { get; set; } = null; | ||||
|  | ||||
|     private Random random = new(); | ||||
|  | ||||
|     private INetworkCommunicatorServer? networkServer = null; | ||||
|     private ILogger? logger = null; | ||||
|     private SoundEffectInstance? scoreSoundEffect = null; | ||||
|     private SoundEffectInstance? gameEndSoundEffect = null; | ||||
|  | ||||
|     public int ScoreLeft { get; private set; } = 0; | ||||
|     public int ScoreRight { get; private set; } = 0; | ||||
|     public int ScoreSum => ScoreLeft + ScoreRight; | ||||
|  | ||||
|     public int WinScore { get; } = 5; | ||||
|     public Ball Ball { get; private set; } = null!; | ||||
|     public bool IsGameInProgress { get; private set; } = false; | ||||
|  | ||||
|     public PongManager() => WinScore = 5; | ||||
|     public PongManager(int winScore) => WinScore = winScore; | ||||
|  | ||||
|     public void FirstActiveFrame() | ||||
|     { | ||||
|         Ball = Universe.FindRequiredBehaviour<Ball>(); | ||||
|         networkServer = Universe.FindBehaviour<INetworkCommunicatorServer>(); | ||||
|         logger = Universe.FindBehaviour<ILogger>(); | ||||
|     } | ||||
|  | ||||
|     public void LoadContent(ContentManager content) | ||||
|     { | ||||
|         gameEndSoundEffect = content.Load<SoundEffect>("Audio/Win").CreateInstance(); | ||||
|         scoreSoundEffect = content.Load<SoundEffect>("Audio/Score").CreateInstance(); | ||||
|     } | ||||
|  | ||||
|     public void ScoreToLeft() | ||||
|     { | ||||
|         ScoreLeft++; | ||||
|         PostScoreUpdate(); | ||||
|     } | ||||
|  | ||||
|     public void ScoreToRight() | ||||
|     { | ||||
|         ScoreRight++; | ||||
|         PostScoreUpdate(); | ||||
|     } | ||||
|  | ||||
|     public bool Start() | ||||
|     { | ||||
|         if (networkServer is null) | ||||
|             return false; | ||||
|  | ||||
|         if (Ball.RigidBody.Velocity.MagnitudeSquared > 0.01f) | ||||
|             return false; | ||||
|  | ||||
|         Reset(); | ||||
|         IsGameInProgress = true; | ||||
|         PostScoreUpdate(); | ||||
|         networkServer.SendToAll(new StartPacket()); | ||||
|         logger?.Log(this, $"Game started"); | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     public void Reset() | ||||
|     { | ||||
|         ScoreLeft = ScoreRight = 0; | ||||
|         IsGameInProgress = false; | ||||
|  | ||||
|         Ball.ResetBall(); | ||||
|  | ||||
|         OnReset?.Invoke(this); | ||||
|     } | ||||
|  | ||||
|     private void PostScoreUpdate() | ||||
|     { | ||||
|         OnScoreUpdated?.Invoke(this); | ||||
|         Ball.ResetBall(); | ||||
|  | ||||
|         if (networkServer is not null) | ||||
|         { | ||||
|             networkServer.SendToAll(new ScorePacket(this)); | ||||
|             logger?.Log(this, $"Sending score update packet to all: {ScoreLeft} - {ScoreRight}"); | ||||
|         } | ||||
|  | ||||
|         int halfwayScore = (int)(WinScore * .5f); | ||||
|         if (ScoreLeft > halfwayScore || ScoreRight > halfwayScore) | ||||
|         { | ||||
|             IsGameInProgress = false; | ||||
|             gameEndSoundEffect?.Play(); | ||||
|             OnFinished?.Invoke(this); | ||||
|             logger?.Log(this, $"Game finished: {ScoreLeft} - {ScoreRight}"); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         Ball.LaunchBall(GetBallLaunchDirection()); | ||||
|     } | ||||
|  | ||||
|     private Vector2D GetBallLaunchDirection() | ||||
|     { | ||||
|         const float AllowedRadians = 45f * Engine.Core.Math.DegreeToRadian; | ||||
|         float rotation = (float)random.NextDouble() * 2f * AllowedRadians - AllowedRadians; | ||||
|         bool isBackwards = (random.Next() % 2) == 1; | ||||
|         return Vector2D.Right.Rotate(isBackwards ? rotation + Engine.Core.Math.Pi : rotation); | ||||
|     } | ||||
|  | ||||
|     void IPacketListenerClient<ScorePacket>.OnClientPacketArrived(IConnection sender, ScorePacket packet) | ||||
|     { | ||||
|         ScoreLeft = packet.Left; | ||||
|         ScoreRight = packet.Right; | ||||
|  | ||||
|         PostScoreUpdate(); | ||||
|  | ||||
|         if (IsGameInProgress && (ScoreLeft != 0 || ScoreRight != 0)) | ||||
|             scoreSoundEffect?.Play(); | ||||
|  | ||||
|         logger?.Log(this, $"Client score update packet arrived: {packet.Left} - {packet.Right}"); | ||||
|     } | ||||
|  | ||||
|     void IPacketListenerClient<StartPacket>.OnClientPacketArrived(IConnection sender, StartPacket packet) | ||||
|     { | ||||
|         IsGameInProgress = true; | ||||
|         logger?.Log(this, $"Game started"); | ||||
|     } | ||||
|  | ||||
|     private class StartPacket : INetworkPacket; | ||||
|     private class ScorePacket : INetworkPacket | ||||
|     { | ||||
|         public int Left { get; set; } | ||||
|         public int Right { get; set; } | ||||
|  | ||||
|         public ScorePacket() { } | ||||
|         public ScorePacket(PongManager pongManagerBehaviour) | ||||
|         { | ||||
|             Left = pongManagerBehaviour.ScoreLeft; | ||||
|             Right = pongManagerBehaviour.ScoreRight; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -1,28 +0,0 @@ | ||||
| using Engine.Core; | ||||
|  | ||||
| namespace Pong.Behaviours; | ||||
|  | ||||
| public class ScoreLabel(bool IsLeft) : Label, IFirstFrameUpdate | ||||
| { | ||||
|     public readonly bool IsLeft = IsLeft; | ||||
|  | ||||
|     private PongManager pongManager = null!; | ||||
|  | ||||
|     public void FirstActiveFrame() | ||||
|     { | ||||
|         pongManager = Universe.FindRequiredBehaviour<PongManager>(); | ||||
|  | ||||
|         pongManager.OnScoreUpdated += UpdateScores; | ||||
|         pongManager.OnReset += UpdateScores; | ||||
|  | ||||
|         UpdateScores(pongManager); | ||||
|     } | ||||
|  | ||||
|     private void UpdateScores(PongManager pongManager) | ||||
|     { | ||||
|         if (IsLeft) | ||||
|             Text = pongManager.ScoreLeft.ToString(); | ||||
|         else | ||||
|             Text = pongManager.ScoreRight.ToString(); | ||||
|     } | ||||
| } | ||||
| @@ -1,19 +0,0 @@ | ||||
| using System; | ||||
|  | ||||
| using Engine.Core; | ||||
| using Engine.Physics2D; | ||||
|  | ||||
| namespace Pong.Behaviours; | ||||
|  | ||||
| public class ScoreWall(Action OnCollision) : Behaviour2D, IFirstFrameUpdate | ||||
| { | ||||
|     private Action OnCollision { get; } = OnCollision; | ||||
|  | ||||
|     public void FirstActiveFrame() | ||||
|     { | ||||
|         if (!BehaviourController.TryGetBehaviour(out ICollider2D? collider2D)) | ||||
|             return; | ||||
|  | ||||
|         collider2D.OnCollisionDetected.AddListener((_, _1) => OnCollision?.Invoke()); | ||||
|     } | ||||
| } | ||||
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							| @@ -1,128 +0,0 @@ | ||||
| using System; | ||||
|  | ||||
| using Microsoft.Xna.Framework.Input; | ||||
|  | ||||
| using Pong.Behaviours; | ||||
|  | ||||
| using Engine.Core; | ||||
| using Engine.Core.Factory; | ||||
| using Engine.Integration.MonoGame; | ||||
| using Engine.Systems.Network; | ||||
| using Engine.Physics2D; | ||||
| using Engine.Systems.Tween; | ||||
|  | ||||
| namespace Pong; | ||||
|  | ||||
| public static class PongUniverse | ||||
| { | ||||
|     public static IUniverse ApplyPongClient(Universe universe, string server, int port) | ||||
|     { | ||||
|         LiteNetLibClient client = universe.InstantiateUniverseObject().SetUniverseObject("Client").BehaviourController.AddBehaviour<LiteNetLibClient>(); | ||||
|         client.BehaviourController.AddBehaviour<NetworkManager>(); | ||||
|         universe.OnPreUpdate.AddOneTimeListener((_, _) => client.Connect(server, port)); | ||||
|  | ||||
|         DrawManager drawManager = universe.InstantiateUniverseObject().SetUniverseObject("Draw Manager").BehaviourController.AddBehaviour<DrawManager>(); | ||||
|         universe.InstantiateUniverseObject().SetUniverseObject("Triangle Batcher", drawManager.UniverseObject).BehaviourController.AddBehaviour<TriangleBatcher>(); | ||||
|         universe.InstantiateUniverseObject().SetUniverseObject("Sprite Batcher", drawManager.UniverseObject).BehaviourController.AddBehaviour<SpriteBatcher>(); | ||||
|  | ||||
|         //////////////////////////////////////////////////////////////////////////////////// | ||||
|  | ||||
|         universe.InstantiateUniverseObject().SetUniverseObject("Camera") | ||||
|             .BehaviourController.AddBehaviour<Transform2D>() | ||||
|             .BehaviourController.AddBehaviour<CameraController>() | ||||
|             .BehaviourController.AddBehaviour<MonoGameCamera2D>(); | ||||
|  | ||||
|         //////////////////////////////////////////////////////////////////////////////////// | ||||
|  | ||||
|         universe.InstantiateUniverseObject().SetUniverseObject("Score Left") | ||||
|             .BehaviourController.AddBehaviour<Transform2D>().SetTransform(position: new Vector2D(-250f, 250f), scale: Vector2D.One * .25f) | ||||
|             .BehaviourController.AddBehaviour<ScoreLabel>(true); | ||||
|  | ||||
|         universe.InstantiateUniverseObject().SetUniverseObject("Score Right") | ||||
|             .BehaviourController.AddBehaviour<Transform2D>().SetTransform(position: new Vector2D(250f, 250f), scale: Vector2D.One * .25f) | ||||
|             .BehaviourController.AddBehaviour<ScoreLabel>(false); | ||||
|  | ||||
|         return universe; | ||||
|     } | ||||
|  | ||||
|     public static IUniverse ApplyPongServer(Universe universe, int port) | ||||
|     { | ||||
|         LiteNetLibServer server = universe.InstantiateUniverseObject().SetUniverseObject("Server").BehaviourController.AddBehaviour<LiteNetLibServer>(); | ||||
|         server.BehaviourController.AddBehaviour<NetworkManager>(); | ||||
|         universe.OnPreUpdate.AddOneTimeListener((_, _) => server.Start(port, 2)); | ||||
|  | ||||
|         return universe; | ||||
|     } | ||||
|  | ||||
|     public static IUniverse ApplyPongUniverse(Universe universe) | ||||
|     { | ||||
|         universe.InstantiateUniverseObject().SetUniverseObject("Update Manager").BehaviourController.AddBehaviour<UpdateManager>(); | ||||
|         universe.InstantiateUniverseObject().SetUniverseObject("Coroutine Manager").BehaviourController.AddBehaviour<CoroutineManager>(); | ||||
|         universe.InstantiateUniverseObject().SetUniverseObject("Tween Manager").BehaviourController.AddBehaviour<TweenManager>(); | ||||
|         universe.InstantiateUniverseObject().SetUniverseObject("Physics Engine 2D").BehaviourController.AddBehaviour<PhysicsEngine2D>(); | ||||
|  | ||||
|         //////////////////////////////////////////////////////////////////////////////////// | ||||
|  | ||||
|         PongManager pongManager = universe.InstantiateUniverseObject().SetUniverseObject("Pong Game Manager") | ||||
|             .BehaviourController.AddBehaviour<PongManager>(5); | ||||
|  | ||||
|         universe.InstantiateUniverseObject().SetUniverseObject("Pong Game Starter", parent: pongManager.UniverseObject) | ||||
|             .BehaviourController.AddBehaviour<PongGameStarter>() | ||||
|             .BehaviourController.AddBehaviour<Transform2D>().SetTransform(position: new Vector2D(-24, 250f), scale: Vector2D.One * .5f) | ||||
|             .BehaviourController.AddBehaviour<Label>(); | ||||
|  | ||||
|         //////////////////////////////////////////////////////////////////////////////////// | ||||
|  | ||||
|         universe.InstantiateUniverseObject().SetUniverseObject("Ball") | ||||
|                 .BehaviourController.AddBehaviour<Transform2D>().SetTransform(position: new Vector2D(0, 0f), scale: new Vector2D(10f, 10f)) | ||||
|                 .BehaviourController.AddBehaviour<DrawableColliderCircle>(new Circle(Vector2D.Zero, 1f)) | ||||
|                 .BehaviourController.AddBehaviour<Ball>() | ||||
|                 .BehaviourController.AddBehaviour<RigidBody2D>(); | ||||
|  | ||||
|         //////////////////////////////////////////////////////////////////////////////////// | ||||
|  | ||||
|         IUniverseObject leftPaddle = UniverseObjectFactory.Instantiate().SetUniverseObject("Left Paddle"); | ||||
|         leftPaddle.BehaviourController.AddBehaviour<Transform2D>().SetTransform(position: new Vector2D(-468f, 0f), scale: new Vector2D(15f, 60f)) | ||||
|                 .BehaviourController.AddBehaviour<DrawableColliderShape>(Shape2D.Square) | ||||
|                 .BehaviourController.AddBehaviour<RigidBody2D>().IsStatic = true; | ||||
|         Paddle leftPaddleBehaviour = BehaviourFactory.Instantiate<Paddle>(Keys.W, Keys.S, 228f, -228f, 400f); | ||||
|         leftPaddleBehaviour.Id = "lp"; | ||||
|         leftPaddle.BehaviourController.AddBehaviour(leftPaddleBehaviour); | ||||
|         universe.Register(leftPaddle); | ||||
|  | ||||
|         IUniverseObject rightPaddle = UniverseObjectFactory.Instantiate().SetUniverseObject("Right Paddle"); | ||||
|         rightPaddle.BehaviourController.AddBehaviour<Transform2D>().SetTransform(position: new Vector2D(468f, 0f), scale: new Vector2D(15f, 60f)) | ||||
|                 .BehaviourController.AddBehaviour<DrawableColliderShape>(Shape2D.Square) | ||||
|                 .BehaviourController.AddBehaviour<RigidBody2D>().IsStatic = true; | ||||
|         Paddle rightPaddleBehaviour = BehaviourFactory.Instantiate<Paddle>(Keys.Up, Keys.Down, 228f, -228f, 400f); | ||||
|         rightPaddleBehaviour.Id = "rp"; | ||||
|         rightPaddle.BehaviourController.AddBehaviour(rightPaddleBehaviour); | ||||
|         universe.Register(rightPaddle); | ||||
|  | ||||
|         //////////////////////////////////////////////////////////////////////////////////// | ||||
|  | ||||
|         universe.InstantiateUniverseObject().SetUniverseObject("Wall Top") | ||||
|             .BehaviourController.AddBehaviour<Transform2D>().SetTransform(position: new Vector2D(0f, 308f), scale: new Vector2D(552f, 20f)) | ||||
|             .BehaviourController.AddBehaviour<DrawableColliderShape>(Shape2D.Square) | ||||
|             .BehaviourController.AddBehaviour<RigidBody2D>().IsStatic = true; | ||||
|  | ||||
|         universe.InstantiateUniverseObject().SetUniverseObject("Wall Bottom") | ||||
|             .BehaviourController.AddBehaviour<Transform2D>().SetTransform(position: new Vector2D(0f, -308f), scale: new Vector2D(552f, 20f)) | ||||
|             .BehaviourController.AddBehaviour<DrawableColliderShape>(Shape2D.Square) | ||||
|             .BehaviourController.AddBehaviour<RigidBody2D>().IsStatic = true; | ||||
|  | ||||
|         universe.InstantiateUniverseObject().SetUniverseObject("Wall Right") | ||||
|             .BehaviourController.AddBehaviour<Transform2D>().SetTransform(position: new Vector2D(532f, 0f), scale: new Vector2D(20f, 328f)) | ||||
|             .BehaviourController.AddBehaviour<ScoreWall>((Action)pongManager.ScoreToLeft) | ||||
|             .BehaviourController.AddBehaviour<DrawableColliderShape>(Shape2D.Square) | ||||
|             .BehaviourController.AddBehaviour<RigidBody2D>().IsStatic = true; | ||||
|  | ||||
|         universe.InstantiateUniverseObject().SetUniverseObject("Wall Left") | ||||
|             .BehaviourController.AddBehaviour<Transform2D>().SetTransform(position: new Vector2D(-532f, 0f), scale: new Vector2D(20f, 328f)) | ||||
|             .BehaviourController.AddBehaviour<ScoreWall>((Action)pongManager.ScoreToRight) | ||||
|             .BehaviourController.AddBehaviour<DrawableColliderShape>(Shape2D.Square) | ||||
|             .BehaviourController.AddBehaviour<RigidBody2D>().IsStatic = true; | ||||
|  | ||||
|         return universe; | ||||
|     } | ||||
| } | ||||
| @@ -1,18 +0,0 @@ | ||||
| <Project Sdk="Microsoft.NET.Sdk"> | ||||
|   <PropertyGroup> | ||||
|     <TargetFramework>net9.0</TargetFramework> | ||||
|     <Nullable>enable</Nullable> | ||||
|     <RootNamespace>Pong.Shared</RootNamespace> | ||||
|     <AssemblyName>Pong.Shared</AssemblyName> | ||||
|   </PropertyGroup> | ||||
|   <ItemGroup> | ||||
|     <PackageReference Include="MonoGame.Framework.DesktopGL" Version="3.8.2.1105"> | ||||
|       <PrivateAssets>All</PrivateAssets> | ||||
|     </PackageReference> | ||||
|   </ItemGroup> | ||||
|   <ItemGroup> | ||||
|     <ProjectReference Include="../Engine/Engine/Engine.csproj" /> | ||||
|     <ProjectReference Include="../Engine/Engine.Integration/Engine.Integration.MonoGame/Engine.Integration.MonoGame.csproj" /> | ||||
|     <ProjectReference Include="../Engine/Engine.Integration/Engine.Integration.LiteNetLib/Engine.Integration.LiteNetLib.csproj" /> | ||||
|   </ItemGroup> | ||||
| </Project> | ||||
		Reference in New Issue
	
	Block a user