Compare commits
	
		
			162 Commits
		
	
	
		
			breaking-c
			...
			feat/liten
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 64ee9a0789 | |||
| 452ce426a0 | |||
| ad5f424298 | |||
| 9302c7e867 | |||
| 80725f454f | |||
| fcc5350b56 | |||
| 1bf8238925 | |||
| b641ebde08 | |||
| 9bf6cabe23 | |||
| cd66eeeeef | |||
| 9f6958e5ba | |||
| 42394f4625 | |||
| 22f96458a6 | |||
| a76905f31e | |||
| e9ca71b87e | |||
| 46991699a1 | |||
| 08f52e9b72 | |||
| 9f8578af9b | |||
| ac9cb72914 | |||
| 875f865bd3 | |||
| 15958ad402 | |||
| 1230dc84ab | |||
| 5d8f5d39be | |||
| ceea23c5ae | |||
| afd4ae8327 | |||
| d41246b6f6 | |||
| 0ec047cc23 | |||
| b238235c15 | |||
| 9c90a804c3 | |||
| 5cfed3ba56 | |||
| bc6aaa865a | |||
| 5df09f64e2 | |||
| abc467d1ea | |||
| 43c4eb6e4c | |||
| 0047111244 | |||
| 92357627a1 | |||
| 23fa1f06e9 | |||
| d89af5ccad | |||
| 7cc3bb4d83 | |||
| 997ac72c4e | |||
| 0987bf7e91 | |||
| 648be2738f | |||
| 43875a6069 | |||
| 41f6dba5e4 | |||
| 2294c06bf9 | |||
| b835fb1582 | |||
| a0a3d97395 | |||
| 4710b8364c | |||
| 29df4a36e9 | |||
| 1ff26f5be4 | |||
| e27b825990 | |||
| 4824496f1a | |||
| f3b7ccaf70 | |||
| 475d82ba02 | |||
| b3dd0f72a4 | |||
| f3ff1b74d2 | |||
| 8901a5469f | |||
| 52682d42b6 | |||
| 0acd119099 | |||
| 3c38cb4159 | |||
| 59059fa09d | |||
| cbda44c2d5 | |||
| f20aabcacf | |||
| da284eda95 | |||
| d0ef2ef224 | |||
| bddf00ce7a | |||
| 29829bbaa6 | |||
| 12f4950ffb | |||
| 0da5ac6f57 | |||
| 79922fadbe | |||
| 0f0180d435 | |||
| ed6f783180 | |||
| 2853a6130b | |||
| 8f9c9f77f0 | |||
| 2b29636b4f | |||
| 4f3a2b4a4e | |||
| 57868ce178 | |||
| 214c37e63f | |||
| 54bdcd93b2 | |||
| 721d63cf66 | |||
| 03082ab43b | |||
| 6591326b70 | |||
| 0153d4cf69 | |||
| 94f7d4acfd | |||
| 23a0c8e893 | |||
| cd3e23b427 | |||
| d13233ce77 | |||
| 34aa4dbb69 | |||
| 51854a3e59 | |||
| 67e46cdaf3 | |||
| 73ae55e1d4 | |||
| a35e25eb31 | |||
| 775f24c560 | |||
| 257e414c2a | |||
| 0cb8170530 | |||
| bbf71f0be6 | |||
| 41a17219b6 | |||
| 29e79cdf26 | |||
| b7a4fe9cb0 | |||
| da83802427 | |||
| 364c383e08 | |||
| 1fd8060857 | |||
| 35933dfd14 | |||
| d66b119119 | |||
| e7ee460323 | |||
| e86cf71010 | |||
| a357f0fdcb | |||
| ff3202eda9 | |||
| 8929d3282f | |||
| bc7925dbab | |||
| 80ee5d760a | |||
| de2d5fb446 | |||
| 753c0031cd | |||
| a734f52b38 | |||
| 4cb9c7dc8d | |||
| fe4618abd3 | |||
| 283556d329 | |||
| 5ef3d491c3 | |||
| 46f589d3aa | |||
| b7d49e41c3 | |||
| 677fec7acc | |||
| a9c7b8b660 | |||
| 958a75552f | |||
| 3717701171 | |||
| 4e95a3a420 | |||
| ad60412d5f | |||
| 0b2158cc7b | |||
| 3580469a07 | |||
| a7e8787579 | |||
| 45df32dabb | |||
| b3af693678 | |||
| c87827d1ef | |||
| c2d2e1fd52 | |||
| 7ad2cc5912 | |||
| ca92b12833 | |||
| fbe3087502 | |||
| ef347320fd | |||
| 1207d04d50 | |||
| 26f11b5cc0 | |||
| 481a49bb52 | |||
| ffe4fc044e | |||
| 91b05c97c4 | |||
| 2f500bef19 | |||
| 7ed6c1e050 | |||
| bd9974f410 | |||
| 42b427f49b | |||
| ef08eedc34 | |||
| 9eed074025 | |||
| 427ab5ed54 | |||
| e252d8fbb2 | |||
| 80c0f4cdd6 | |||
| 91ad13628c | |||
| 76484017e1 | |||
| faf30b8227 | |||
| bf825fd961 | |||
| 6e6475f8bf | |||
| 5b484eb38c | |||
| 04653711e9 | |||
| 40903eacc3 | |||
| a70a934b3d | |||
| 8ea76f91f6 | |||
| 11074b89d5 | 
							
								
								
									
										484
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,484 @@
 | 
			
		||||
## 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
 | 
			
		||||
							
								
								
									
										80
									
								
								.vscode/launch.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,80 @@
 | 
			
		||||
{
 | 
			
		||||
  "version": "0.2.0",
 | 
			
		||||
  "configurations": [
 | 
			
		||||
    {
 | 
			
		||||
      "name": ".NET Launch (Client) 1",
 | 
			
		||||
      "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 (Client) 2",
 | 
			
		||||
      "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"
 | 
			
		||||
      ]
 | 
			
		||||
    }
 | 
			
		||||
  ]
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										33
									
								
								.vscode/tasks.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,33 @@
 | 
			
		||||
{
 | 
			
		||||
  "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",
 | 
			
		||||
      "group": {
 | 
			
		||||
        "kind": "build",
 | 
			
		||||
        "isDefault": true
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  ]
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										16
									
								
								Dockerfile
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,16 @@
 | 
			
		||||
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
									
									
									
									
									
								
							
							
								
								
								
								
								
							
						
						
							
								
								
									
										27
									
								
								Game/.vscode/launch.json
									
									
									
									
										vendored
									
									
								
							
							
						
						@@ -1,27 +0,0 @@
 | 
			
		||||
{
 | 
			
		||||
  // 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 Core Launch (console)",
 | 
			
		||||
      "type": "coreclr",
 | 
			
		||||
      "request": "launch",
 | 
			
		||||
      "preLaunchTask": "build",
 | 
			
		||||
      // If you have changed target frameworks, make sure to update the program path.
 | 
			
		||||
      "program": "${workspaceFolder}/bin/Debug/net8.0/${workspaceFolderBasename}.dll",
 | 
			
		||||
      "args": [],
 | 
			
		||||
      "cwd": "${workspaceFolder}",
 | 
			
		||||
      // For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console
 | 
			
		||||
      "console": "internalConsole",
 | 
			
		||||
      "stopAtEntry": false
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "name": ".NET Core Attach",
 | 
			
		||||
      "type": "coreclr",
 | 
			
		||||
      "request": "attach",
 | 
			
		||||
      "processId": "${command:pickProcess}"
 | 
			
		||||
    }
 | 
			
		||||
  ]
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										7
									
								
								Game/.vscode/settings.json
									
									
									
									
										vendored
									
									
								
							
							
						
						@@ -1,7 +0,0 @@
 | 
			
		||||
{
 | 
			
		||||
    "cSpell.words": [
 | 
			
		||||
        "AABB",
 | 
			
		||||
        "DAABB",
 | 
			
		||||
        "Syntriax"
 | 
			
		||||
    ]
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										15
									
								
								Game/.vscode/tasks.json
									
									
									
									
										vendored
									
									
								
							
							
						
						@@ -1,15 +0,0 @@
 | 
			
		||||
{
 | 
			
		||||
  "version": "2.0.0",
 | 
			
		||||
  "tasks": [
 | 
			
		||||
    {
 | 
			
		||||
      "type": "dotnet",
 | 
			
		||||
      "task": "build",
 | 
			
		||||
      "problemMatcher": ["$msCompile"],
 | 
			
		||||
      "group": {
 | 
			
		||||
        "kind": "build",
 | 
			
		||||
        "isDefault": true
 | 
			
		||||
      },
 | 
			
		||||
      "label": "build"
 | 
			
		||||
    }
 | 
			
		||||
  ]
 | 
			
		||||
}
 | 
			
		||||
@@ -1,107 +0,0 @@
 | 
			
		||||
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;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,106 +0,0 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
using Microsoft.Xna.Framework;
 | 
			
		||||
using Microsoft.Xna.Framework.Graphics;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
using Syntriax.Engine.Core.Abstract;
 | 
			
		||||
 | 
			
		||||
namespace Pong.Behaviours;
 | 
			
		||||
 | 
			
		||||
public class MonoGameCameraBehaviour : BehaviourOverride, ICamera
 | 
			
		||||
{
 | 
			
		||||
    public Action<ICamera>? OnPositionChanged { get; set; } = null;
 | 
			
		||||
    public Action<ICamera>? OnMatrixTransformChanged { get; set; } = null;
 | 
			
		||||
    public Action<ICamera>? OnViewportChanged { get; set; } = null;
 | 
			
		||||
    public Action<ICamera>? OnRotationChanged { get; set; } = null;
 | 
			
		||||
    public Action<ICamera>? OnZoomChanged { get; set; } = null;
 | 
			
		||||
 | 
			
		||||
    private Matrix _matrixTransform = Matrix.Identity;
 | 
			
		||||
 | 
			
		||||
    private Viewport _viewport = default;
 | 
			
		||||
 | 
			
		||||
    private float _zoom = 1f;
 | 
			
		||||
 | 
			
		||||
    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 = value >= .1f ? value : .1f;
 | 
			
		||||
 | 
			
		||||
            if (_zoom == newValue)
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            _zoom = newValue;
 | 
			
		||||
            OnZoomChanged?.Invoke(this);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public float Rotation
 | 
			
		||||
    {
 | 
			
		||||
        get => Transform.Rotation;
 | 
			
		||||
        set => Transform.Rotation = value;
 | 
			
		||||
    }
 | 
			
		||||
    public Action<IAssignableTransform>? OnTransformAssigned { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
 | 
			
		||||
 | 
			
		||||
    ITransform IAssignableTransform.Transform => throw new NotImplementedException();
 | 
			
		||||
 | 
			
		||||
    public void Update()
 | 
			
		||||
    {
 | 
			
		||||
        MatrixTransform =
 | 
			
		||||
            Matrix.CreateTranslation(new Vector3(-Position.X, Position.Y, 0f)) *
 | 
			
		||||
            Matrix.CreateRotationZ(Rotation) *
 | 
			
		||||
            Matrix.CreateScale(Zoom) *
 | 
			
		||||
            Matrix.CreateTranslation(new Vector3(_viewport.Width * .5f, _viewport.Height * .5f, 0f));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected override void OnInitialize()
 | 
			
		||||
    {
 | 
			
		||||
        Transform.OnRotationChanged += OnTransformRotationChanged;
 | 
			
		||||
        Transform.OnPositionChanged += OnTransformPositionChanged;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected override void OnFinalize()
 | 
			
		||||
    {
 | 
			
		||||
        Transform.OnRotationChanged -= OnTransformRotationChanged;
 | 
			
		||||
        Transform.OnPositionChanged -= OnTransformPositionChanged;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void OnTransformRotationChanged(ITransform _) => OnRotationChanged?.Invoke(this);
 | 
			
		||||
    private void OnTransformPositionChanged(ITransform _) => OnPositionChanged?.Invoke(this);
 | 
			
		||||
 | 
			
		||||
    public bool Assign(ITransform transform) => GameObject.Assign(transform);
 | 
			
		||||
}
 | 
			
		||||
@@ -1,50 +0,0 @@
 | 
			
		||||
using System;
 | 
			
		||||
using Microsoft.Xna.Framework;
 | 
			
		||||
using Microsoft.Xna.Framework.Input;
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
using Syntriax.Engine.Input;
 | 
			
		||||
using Syntriax.Engine.Physics2D.Abstract;
 | 
			
		||||
 | 
			
		||||
namespace Pong.Behaviours;
 | 
			
		||||
public class MovementBallBehaviour(Vector2D StartDirection, float Speed) : BehaviourOverride
 | 
			
		||||
{
 | 
			
		||||
    public Vector2D StartDirection { get; private set; } = Vector2D.Normalize(StartDirection);
 | 
			
		||||
    public float Speed { get; set; } = Speed;
 | 
			
		||||
 | 
			
		||||
    protected override void OnFirstActiveFrame()
 | 
			
		||||
    {
 | 
			
		||||
        if (!BehaviourController.TryGetBehaviour(out IRigidBody2D? rigidBody))
 | 
			
		||||
            throw new Exception($"Where's my {nameof(IRigidBody2D)}????");
 | 
			
		||||
 | 
			
		||||
        rigidBody.Velocity = StartDirection * Speed;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // protected override void OnUpdate(GameTime time)
 | 
			
		||||
    // {
 | 
			
		||||
    //     GameObject.Transform.Position += StartDirection * (time.ElapsedGameTime.Nanoseconds * .001f) * Speed;
 | 
			
		||||
 | 
			
		||||
    //     float absY = MathF.Abs(GameObject.Transform.Position.Y);
 | 
			
		||||
    //     float differenceY = absY - PlayAreaBehaviour.PlayArea.Y * 0.5f;
 | 
			
		||||
    //     if (differenceY > 0f)
 | 
			
		||||
    //     {
 | 
			
		||||
    //         if (GameObject.Transform.Position.Y > 0f)
 | 
			
		||||
    //             GameObject.Transform.Position -= Vector2.UnitY * differenceY * 2f;
 | 
			
		||||
    //         else
 | 
			
		||||
    //             GameObject.Transform.Position += Vector2.UnitY * differenceY * 2f;
 | 
			
		||||
 | 
			
		||||
    //         StartDirection = new(StartDirection.X, -StartDirection.Y);
 | 
			
		||||
    //     }
 | 
			
		||||
 | 
			
		||||
    //     float absX = MathF.Abs(GameObject.Transform.Position.X);
 | 
			
		||||
    //     float differenceX = absX - PlayAreaBehaviour.PlayArea.X * 0.5f;
 | 
			
		||||
    //     if (differenceX > 0f)
 | 
			
		||||
    //     {
 | 
			
		||||
    //         if (GameObject.Transform.Position.X > 0f)
 | 
			
		||||
    //             GameObject.Transform.Position -= Vector2.UnitX * differenceX * 2f;
 | 
			
		||||
    //         else
 | 
			
		||||
    //             GameObject.Transform.Position += Vector2.UnitX * differenceX * 2f;
 | 
			
		||||
 | 
			
		||||
    //         StartDirection = new(-StartDirection.X, StartDirection.Y);
 | 
			
		||||
    //     }
 | 
			
		||||
    // }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,62 +0,0 @@
 | 
			
		||||
using System;
 | 
			
		||||
using Microsoft.Xna.Framework;
 | 
			
		||||
using Microsoft.Xna.Framework.Input;
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
using Syntriax.Engine.Input;
 | 
			
		||||
 | 
			
		||||
namespace Pong.Behaviours;
 | 
			
		||||
 | 
			
		||||
public class MovementBoxBehaviour(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!;
 | 
			
		||||
 | 
			
		||||
    protected override void OnUpdate()
 | 
			
		||||
    {
 | 
			
		||||
        if (isUpPressed && isDownPressed)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        if (isUpPressed)
 | 
			
		||||
            GameObject.Transform.Position = GameObject.Transform.Position + Vector2D.Up * (float)Time.Elapsed.TotalSeconds * Speed;
 | 
			
		||||
        else if (isDownPressed)
 | 
			
		||||
            GameObject.Transform.Position = GameObject.Transform.Position + -Vector2D.Up * (float)Time.Elapsed.TotalSeconds * Speed;
 | 
			
		||||
 | 
			
		||||
        GameObject.Transform.Position = new Vector2D(GameObject.Transform.Position.X, MathF.Max(MathF.Min(GameObject.Transform.Position.Y, High), Low));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected override void OnFirstActiveFrame()
 | 
			
		||||
    {
 | 
			
		||||
        if (!BehaviourController.TryGetBehaviour<IButtonInputs<Keys>>(out var behaviourResult))
 | 
			
		||||
            throw new Exception($"{nameof(IButtonInputs<Keys>)} is missing on ${GameObject.Name}.");
 | 
			
		||||
 | 
			
		||||
        inputs = behaviourResult;
 | 
			
		||||
 | 
			
		||||
        inputs.RegisterOnPress(Up, OnUpPressed);
 | 
			
		||||
        inputs.RegisterOnRelease(Up, OnUpReleased);
 | 
			
		||||
 | 
			
		||||
        inputs.RegisterOnPress(Down, OnDownPressed);
 | 
			
		||||
        inputs.RegisterOnRelease(Down, OnDownReleased);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected override void OnFinalize()
 | 
			
		||||
    {
 | 
			
		||||
        inputs.UnregisterOnPress(Up, OnUpPressed);
 | 
			
		||||
        inputs.UnregisterOnRelease(Up, OnUpReleased);
 | 
			
		||||
 | 
			
		||||
        inputs.UnregisterOnPress(Down, OnDownPressed);
 | 
			
		||||
        inputs.UnregisterOnRelease(Down, OnDownReleased);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void OnUpPressed(IButtonInputs<Keys> inputs, Keys keys) => isUpPressed = true;
 | 
			
		||||
    private void OnUpReleased(IButtonInputs<Keys> inputs, Keys keys) => isUpPressed = false;
 | 
			
		||||
    private void OnDownPressed(IButtonInputs<Keys> inputs, Keys keys) => isDownPressed = true;
 | 
			
		||||
    private void OnDownReleased(IButtonInputs<Keys> inputs, Keys keys) => isDownPressed = false;
 | 
			
		||||
}
 | 
			
		||||
@@ -1,26 +0,0 @@
 | 
			
		||||
using System;
 | 
			
		||||
using Microsoft.Xna.Framework;
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
namespace Pong.Behaviours;
 | 
			
		||||
 | 
			
		||||
public class PlayAreaBehaviour : BehaviourOverride
 | 
			
		||||
{
 | 
			
		||||
    public Action<PlayAreaBehaviour>? OnPlayAreaChanged { get; set; } = null;
 | 
			
		||||
 | 
			
		||||
    private Vector2 _playArea = Vector2.Zero;
 | 
			
		||||
 | 
			
		||||
    public Vector2 PlayArea
 | 
			
		||||
    {
 | 
			
		||||
        get => _playArea;
 | 
			
		||||
        set
 | 
			
		||||
        {
 | 
			
		||||
            if (_playArea == value)
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            _playArea = value;
 | 
			
		||||
            OnPlayAreaChanged?.Invoke(this);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,63 +0,0 @@
 | 
			
		||||
 | 
			
		||||
#----------------------------- Global Properties ----------------------------#
 | 
			
		||||
 | 
			
		||||
/outputDir:bin/$(Platform)
 | 
			
		||||
/intermediateDir:obj/$(Platform)
 | 
			
		||||
/platform:DesktopGL
 | 
			
		||||
/config:
 | 
			
		||||
/profile:Reach
 | 
			
		||||
/compress:False
 | 
			
		||||
 | 
			
		||||
#-------------------------------- References --------------------------------#
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#---------------------------------- Content ---------------------------------#
 | 
			
		||||
 | 
			
		||||
#begin Sprites/Circle.png
 | 
			
		||||
/importer:TextureImporter
 | 
			
		||||
/processor:TextureProcessor
 | 
			
		||||
/processorParam:ColorKeyColor=255,0,255,255
 | 
			
		||||
/processorParam:ColorKeyEnabled=True
 | 
			
		||||
/processorParam:GenerateMipmaps=False
 | 
			
		||||
/processorParam:PremultiplyAlpha=True
 | 
			
		||||
/processorParam:ResizeToPowerOfTwo=False
 | 
			
		||||
/processorParam:MakeSquare=False
 | 
			
		||||
/processorParam:TextureFormat=Color
 | 
			
		||||
/build:Sprites/Circle.png
 | 
			
		||||
 | 
			
		||||
#begin Sprites/Circle.png
 | 
			
		||||
/importer:TextureImporter
 | 
			
		||||
/processor:TextureProcessor
 | 
			
		||||
/processorParam:ColorKeyColor=255,0,255,255
 | 
			
		||||
/processorParam:ColorKeyEnabled=True
 | 
			
		||||
/processorParam:GenerateMipmaps=False
 | 
			
		||||
/processorParam:PremultiplyAlpha=True
 | 
			
		||||
/processorParam:ResizeToPowerOfTwo=False
 | 
			
		||||
/processorParam:MakeSquare=False
 | 
			
		||||
/processorParam:TextureFormat=Color
 | 
			
		||||
/build:Sprites/Circle.png
 | 
			
		||||
 | 
			
		||||
#begin Sprites/Pixel.png
 | 
			
		||||
/importer:TextureImporter
 | 
			
		||||
/processor:TextureProcessor
 | 
			
		||||
/processorParam:ColorKeyColor=255,0,255,255
 | 
			
		||||
/processorParam:ColorKeyEnabled=True
 | 
			
		||||
/processorParam:GenerateMipmaps=False
 | 
			
		||||
/processorParam:PremultiplyAlpha=True
 | 
			
		||||
/processorParam:ResizeToPowerOfTwo=False
 | 
			
		||||
/processorParam:MakeSquare=False
 | 
			
		||||
/processorParam:TextureFormat=Color
 | 
			
		||||
/build:Sprites/Pixel.png
 | 
			
		||||
 | 
			
		||||
#begin Sprites/Pixel.png
 | 
			
		||||
/importer:TextureImporter
 | 
			
		||||
/processor:TextureProcessor
 | 
			
		||||
/processorParam:ColorKeyColor=255,0,255,255
 | 
			
		||||
/processorParam:ColorKeyEnabled=True
 | 
			
		||||
/processorParam:GenerateMipmaps=False
 | 
			
		||||
/processorParam:PremultiplyAlpha=True
 | 
			
		||||
/processorParam:ResizeToPowerOfTwo=False
 | 
			
		||||
/processorParam:MakeSquare=False
 | 
			
		||||
/processorParam:TextureFormat=Color
 | 
			
		||||
/build:Sprites/Pixel.png
 | 
			
		||||
 | 
			
		||||
| 
		 Before Width: | Height: | Size: 3.6 KiB  | 
| 
		 Before Width: | Height: | Size: 546 B  | 
@@ -1,15 +0,0 @@
 | 
			
		||||
using System.Runtime.CompilerServices;
 | 
			
		||||
using Microsoft.Xna.Framework;
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
namespace Pong;
 | 
			
		||||
 | 
			
		||||
public static class EngineConverter
 | 
			
		||||
{
 | 
			
		||||
    [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 Vector2 ToVector2(this Vector2D vector) => new(vector.X, vector.Y);
 | 
			
		||||
}
 | 
			
		||||
@@ -1,34 +0,0 @@
 | 
			
		||||
<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="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" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
  <Target Name="RestoreDotnetTools" BeforeTargets="Restore">
 | 
			
		||||
    <Message Text="Restoring dotnet tools" Importance="High" />
 | 
			
		||||
    <Exec Command="dotnet tool restore" />
 | 
			
		||||
  </Target>
 | 
			
		||||
</Project>
 | 
			
		||||
@@ -1,31 +0,0 @@
 | 
			
		||||
 | 
			
		||||
Microsoft Visual Studio Solution File, Format Version 12.00
 | 
			
		||||
# Visual Studio Version 17
 | 
			
		||||
VisualStudioVersion = 17.5.002.0
 | 
			
		||||
MinimumVisualStudioVersion = 10.0.40219.1
 | 
			
		||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Game", "Game.csproj", "{42644486-9F9E-4242-B6C4-AF31BBFA31D2}"
 | 
			
		||||
EndProject
 | 
			
		||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Engine.Core", "..\Engine\Engine.Core\Engine.Core.csproj", "{EF1FE4A2-40DF-4967-8003-CF6D98010D02}"
 | 
			
		||||
EndProject
 | 
			
		||||
Global
 | 
			
		||||
	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 | 
			
		||||
		Debug|Any CPU = Debug|Any CPU
 | 
			
		||||
		Release|Any CPU = Release|Any CPU
 | 
			
		||||
	EndGlobalSection
 | 
			
		||||
	GlobalSection(ProjectConfigurationPlatforms) = postSolution
 | 
			
		||||
		{42644486-9F9E-4242-B6C4-AF31BBFA31D2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 | 
			
		||||
		{42644486-9F9E-4242-B6C4-AF31BBFA31D2}.Debug|Any CPU.Build.0 = Debug|Any CPU
 | 
			
		||||
		{42644486-9F9E-4242-B6C4-AF31BBFA31D2}.Release|Any CPU.ActiveCfg = Release|Any CPU
 | 
			
		||||
		{42644486-9F9E-4242-B6C4-AF31BBFA31D2}.Release|Any CPU.Build.0 = Release|Any CPU
 | 
			
		||||
		{EF1FE4A2-40DF-4967-8003-CF6D98010D02}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 | 
			
		||||
		{EF1FE4A2-40DF-4967-8003-CF6D98010D02}.Debug|Any CPU.Build.0 = Debug|Any CPU
 | 
			
		||||
		{EF1FE4A2-40DF-4967-8003-CF6D98010D02}.Release|Any CPU.ActiveCfg = Release|Any CPU
 | 
			
		||||
		{EF1FE4A2-40DF-4967-8003-CF6D98010D02}.Release|Any CPU.Build.0 = Release|Any CPU
 | 
			
		||||
	EndGlobalSection
 | 
			
		||||
	GlobalSection(SolutionProperties) = preSolution
 | 
			
		||||
		HideSolutionNode = FALSE
 | 
			
		||||
	EndGlobalSection
 | 
			
		||||
	GlobalSection(ExtensibilityGlobals) = postSolution
 | 
			
		||||
		SolutionGuid = {AB3225EE-1621-439F-8F83-DF4515922FEF}
 | 
			
		||||
	EndGlobalSection
 | 
			
		||||
EndGlobal
 | 
			
		||||
							
								
								
									
										244
									
								
								Game/Game1.cs
									
									
									
									
									
								
							
							
						
						@@ -1,244 +0,0 @@
 | 
			
		||||
using System;
 | 
			
		||||
using Microsoft.Xna.Framework;
 | 
			
		||||
using Microsoft.Xna.Framework.Graphics;
 | 
			
		||||
using Microsoft.Xna.Framework.Input;
 | 
			
		||||
 | 
			
		||||
using Pong.Behaviours;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
using Syntriax.Engine.Core.Abstract;
 | 
			
		||||
using Syntriax.Engine.Graphics.TwoDimensional;
 | 
			
		||||
using Syntriax.Engine.Physics2D;
 | 
			
		||||
using Syntriax.Engine.Physics2D.Primitives;
 | 
			
		||||
 | 
			
		||||
namespace Pong;
 | 
			
		||||
 | 
			
		||||
public class Game1 : Game
 | 
			
		||||
{
 | 
			
		||||
    private GraphicsDeviceManager _graphics = null!;
 | 
			
		||||
    private PhysicsEngine2D engine;
 | 
			
		||||
    private SpriteBatch _spriteBatch = null!;
 | 
			
		||||
    public static GameManager gameManager = null!;
 | 
			
		||||
    public static Sprite spriteBox = null!;
 | 
			
		||||
    private MonoGameCameraBehaviour cameraBehaviour = null!;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    public Game1()
 | 
			
		||||
    {
 | 
			
		||||
        engine = new PhysicsEngine2D();
 | 
			
		||||
 | 
			
		||||
        _graphics = new GraphicsDeviceManager(this)
 | 
			
		||||
        {
 | 
			
		||||
            PreferredBackBufferWidth = 1024,
 | 
			
		||||
            PreferredBackBufferHeight = 576
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        Content.RootDirectory = "Content";
 | 
			
		||||
        IsMouseVisible = true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected override void Initialize()
 | 
			
		||||
    {
 | 
			
		||||
        gameManager = new();
 | 
			
		||||
 | 
			
		||||
        // TODO: Add your initialization logic here
 | 
			
		||||
        gameManager.Initialize();
 | 
			
		||||
 | 
			
		||||
        base.Initialize();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected override void LoadContent()
 | 
			
		||||
    {
 | 
			
		||||
        _spriteBatch = new SpriteBatch(GraphicsDevice);
 | 
			
		||||
 | 
			
		||||
        spriteBox = new Sprite() { Texture2D = Content.Load<Texture2D>("Sprites/Pixel") };
 | 
			
		||||
        Sprite spriteBall = new Sprite() { Texture2D = Content.Load<Texture2D>("Sprites/Circle") };
 | 
			
		||||
 | 
			
		||||
        IGameObject gameObjectCamera = gameManager.InstantiateGameObject<GameObject>();
 | 
			
		||||
        gameObjectCamera.Name = "Camera";
 | 
			
		||||
        gameObjectCamera.Transform.Position = Vector2D.Zero;
 | 
			
		||||
 | 
			
		||||
        cameraBehaviour = gameObjectCamera.BehaviourController.AddBehaviour<MonoGameCameraBehaviour>();
 | 
			
		||||
        cameraBehaviour.Viewport = GraphicsDevice.Viewport;
 | 
			
		||||
        gameManager.Camera = cameraBehaviour;
 | 
			
		||||
 | 
			
		||||
        GameObject gameObjectBall = gameManager.InstantiateGameObject<GameObject>();
 | 
			
		||||
        gameObjectBall.Name = "Ball";
 | 
			
		||||
        gameObjectBall.Transform.Position = Vector2D.Zero;
 | 
			
		||||
        gameObjectBall.Transform.Scale = new Vector2D(1f / 51.2f, 1f / 51.2f);
 | 
			
		||||
        engine.AddRigidBody(gameObjectBall.BehaviourController.AddBehaviour<RigidBody2D>());
 | 
			
		||||
        gameObjectBall.BehaviourController.AddBehaviour<MovementBallBehaviour>(new Vector2D(.1f, .1f), 500f);
 | 
			
		||||
        gameObjectBall.BehaviourController.AddBehaviour<DisplayableSpriteBehaviour>().Assign(spriteBall);
 | 
			
		||||
        gameObjectBall.BehaviourController.AddBehaviour<Collider2DAABBBehaviour>().AABBLocal = new AABB(-Vector2D.One * 512f * .5f, Vector2D.One * 512f * .5f);
 | 
			
		||||
        // gameObjectBall = gameManager.InstantiateGameObject<GameObject>();
 | 
			
		||||
        // gameObjectBall.Name = "Ball";
 | 
			
		||||
        // gameObjectBall.Transform.Position = Vector2D.UnitY * 30f;
 | 
			
		||||
        // gameObjectBall.Transform.Scale = new Vector2D(1f / 51.2f, 1f / 51.2f);
 | 
			
		||||
        // engine.AddRigidBody(gameObjectBall.BehaviourController.AddBehaviour<RigidBody2D>());
 | 
			
		||||
        // gameObjectBall.BehaviourController.AddBehaviour<MovementBallBehaviour>(new Vector2D(.1f, .01f), 500f);
 | 
			
		||||
        // gameObjectBall.BehaviourController.AddBehaviour<DisplayableSpriteBehaviour>().Assign(spriteBall);
 | 
			
		||||
        // gameObjectBall.BehaviourController.AddBehaviour<Collider2DAABBBehaviour>().AABBLocal = new AABB(-Vector2D.One * 512f * .5f, Vector2D.One * 512f * .5f);
 | 
			
		||||
 | 
			
		||||
        // IGameObject gameObjectLeft = gameManager.InstantiateGameObject<GameObject>();
 | 
			
		||||
        // gameObjectLeft.Name = "Left";
 | 
			
		||||
        // gameObjectLeft.Transform.Position = new Vector2D(-452, 0f);
 | 
			
		||||
        // gameObjectLeft.Transform.Scale = new Vector2D(10f, 40f);
 | 
			
		||||
        // gameObjectLeft.BehaviourController.AddBehaviour<KeyboardInputsBehaviour>();
 | 
			
		||||
        // gameObjectLeft.BehaviourController.AddBehaviour<MovementBoxBehaviour>(Keys.W, Keys.S, 268f, -268f, 400f);
 | 
			
		||||
        // gameObjectLeft.BehaviourController.AddBehaviour<DisplayableSpriteBehaviour>().Assign(spriteBox);
 | 
			
		||||
        // gameObjectLeft.BehaviourController.AddBehaviour<Collider2DAABBBehaviour>().AABBLocal = new AABB(-Vector2D.One * .5f, Vector2D.One * .5f);
 | 
			
		||||
        // engine.AddRigidBody(gameObjectLeft.BehaviourController.AddBehaviour<RigidBody2D>());
 | 
			
		||||
 | 
			
		||||
        // IGameObject gameObjectRight = gameManager.InstantiateGameObject<GameObject>();
 | 
			
		||||
        // gameObjectRight.Name = "Right";
 | 
			
		||||
        // gameObjectRight.Transform.Position = new Vector2D(452, 0f);
 | 
			
		||||
        // gameObjectRight.Transform.Scale = new Vector2D(10f, 40f);
 | 
			
		||||
        // gameObjectRight.BehaviourController.AddBehaviour<KeyboardInputsBehaviour>();
 | 
			
		||||
        // gameObjectRight.BehaviourController.AddBehaviour<MovementBoxBehaviour>(Keys.Up, Keys.Down, 268f, -268f, 400f);
 | 
			
		||||
        // gameObjectRight.BehaviourController.AddBehaviour<DisplayableSpriteBehaviour>().Assign(spriteBox);
 | 
			
		||||
        // gameObjectRight.BehaviourController.AddBehaviour<Collider2DAABBBehaviour>().AABBLocal = new AABB(-Vector2D.One * .5f, Vector2D.One * .5f);
 | 
			
		||||
        // engine.AddRigidBody(gameObjectRight.BehaviourController.AddBehaviour<RigidBody2D>());
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        IGameObject goPlayAreaTop = gameManager.InstantiateGameObject<GameObject>();
 | 
			
		||||
        goPlayAreaTop.Transform.Position = new Vector2D(0f, 288f + 20f);
 | 
			
		||||
        goPlayAreaTop.Transform.Scale = new Vector2D(10240f, 40f);
 | 
			
		||||
        goPlayAreaTop.BehaviourController.AddBehaviour<DisplayableSpriteBehaviour>().Assign(spriteBox);
 | 
			
		||||
        goPlayAreaTop.BehaviourController.AddBehaviour<Collider2DAABBBehaviour>().AABBLocal = new AABB(-Vector2D.One * .5f, Vector2D.One * .5f);
 | 
			
		||||
        engine.AddRigidBody(goPlayAreaTop.BehaviourController.AddBehaviour<RigidBody2D>());
 | 
			
		||||
        IGameObject goPlayAreaBottom = gameManager.InstantiateGameObject<GameObject>();
 | 
			
		||||
        goPlayAreaBottom.Transform.Position = new Vector2D(0f, -(288f + 20f));
 | 
			
		||||
        goPlayAreaBottom.Transform.Scale = new Vector2D(10240f, 40f);
 | 
			
		||||
        goPlayAreaBottom.BehaviourController.AddBehaviour<DisplayableSpriteBehaviour>().Assign(spriteBox);
 | 
			
		||||
        goPlayAreaBottom.BehaviourController.AddBehaviour<Collider2DAABBBehaviour>().AABBLocal = new AABB(-Vector2D.One * .5f, Vector2D.One * .5f);
 | 
			
		||||
        engine.AddRigidBody(goPlayAreaBottom.BehaviourController.AddBehaviour<RigidBody2D>());
 | 
			
		||||
 | 
			
		||||
        IGameObject goPlayAreaRight = gameManager.InstantiateGameObject<GameObject>();
 | 
			
		||||
        goPlayAreaRight.Transform.Position = new Vector2D(512f + 20f, 0f);
 | 
			
		||||
        goPlayAreaRight.Transform.Scale = new Vector2D(40f, 5760f);
 | 
			
		||||
        goPlayAreaRight.BehaviourController.AddBehaviour<DisplayableSpriteBehaviour>().Assign(spriteBox);
 | 
			
		||||
        goPlayAreaRight.BehaviourController.AddBehaviour<Collider2DAABBBehaviour>().AABBLocal = new AABB(-Vector2D.One * .5f, Vector2D.One * .5f);
 | 
			
		||||
        engine.AddRigidBody(goPlayAreaRight.BehaviourController.AddBehaviour<RigidBody2D>());
 | 
			
		||||
        IGameObject goPlayAreaLeft = gameManager.InstantiateGameObject<GameObject>();
 | 
			
		||||
        goPlayAreaLeft.Transform.Position = new Vector2D(-(512f + 20f), 0f);
 | 
			
		||||
        goPlayAreaLeft.Transform.Scale = new Vector2D(40f, 5760f);
 | 
			
		||||
        goPlayAreaLeft.BehaviourController.AddBehaviour<DisplayableSpriteBehaviour>().Assign(spriteBox);
 | 
			
		||||
        goPlayAreaLeft.BehaviourController.AddBehaviour<Collider2DAABBBehaviour>().AABBLocal = new AABB(-Vector2D.One * .5f, Vector2D.One * .5f);
 | 
			
		||||
        engine.AddRigidBody(goPlayAreaLeft.BehaviourController.AddBehaviour<RigidBody2D>());
 | 
			
		||||
 | 
			
		||||
        // IGameObject goPlayAreaCenter = gameManager.InstantiateGameObject<GameObject>();
 | 
			
		||||
        // goPlayAreaCenter.Transform.Position = new Vector2D(100f, 100f);
 | 
			
		||||
        // goPlayAreaCenter.Transform.Scale = new Vector2D(40f, 40f);
 | 
			
		||||
        // // goPlayAreaCenter.BehaviourController.AddBehaviour<DisplayableSpriteBehaviour>().Assign(spriteBox);
 | 
			
		||||
        // engine.AddRigidBody(goPlayAreaCenter.BehaviourController.AddBehaviour<RigidBody2D>());
 | 
			
		||||
        // TODO: use this.Content to load your game content here
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected override void Update(GameTime gameTime)
 | 
			
		||||
    {
 | 
			
		||||
        if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape))
 | 
			
		||||
            Exit();
 | 
			
		||||
 | 
			
		||||
        if (Keyboard.GetState().IsKeyDown(Keys.F))
 | 
			
		||||
        {
 | 
			
		||||
            if (_graphics.IsFullScreen)
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            _graphics.PreferMultiSampling = false;
 | 
			
		||||
            _graphics.PreferredBackBufferWidth = GraphicsDevice.Adapter.CurrentDisplayMode.Width;
 | 
			
		||||
            _graphics.PreferredBackBufferHeight = GraphicsDevice.Adapter.CurrentDisplayMode.Height;
 | 
			
		||||
            _graphics.IsFullScreen = true;
 | 
			
		||||
            _graphics.ApplyChanges();
 | 
			
		||||
 | 
			
		||||
            float previousScreenSize = MathF.Sqrt(MathF.Pow(cameraBehaviour.Viewport.Width, 2f) + MathF.Pow(cameraBehaviour.Viewport.Height, 2f));
 | 
			
		||||
            float currentScreenSize = MathF.Sqrt(MathF.Pow(GraphicsDevice.Viewport.Width, 2f) + MathF.Pow(GraphicsDevice.Viewport.Height, 2f));
 | 
			
		||||
            cameraBehaviour.Zoom /= previousScreenSize / currentScreenSize;
 | 
			
		||||
            cameraBehaviour.Viewport = GraphicsDevice.Viewport;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (Keyboard.GetState().IsKeyDown(Keys.U))
 | 
			
		||||
            cameraBehaviour.Zoom += gameTime.ElapsedGameTime.Nanoseconds * 0.00025f;
 | 
			
		||||
        if (Keyboard.GetState().IsKeyDown(Keys.J))
 | 
			
		||||
            cameraBehaviour.Zoom -= gameTime.ElapsedGameTime.Nanoseconds * 0.00025f;
 | 
			
		||||
 | 
			
		||||
        if (Keyboard.GetState().IsKeyDown(Keys.Q))
 | 
			
		||||
            cameraBehaviour.BehaviourController.GameObject.Transform.Rotation += gameTime.ElapsedGameTime.Nanoseconds * 0.000025f;
 | 
			
		||||
        if (Keyboard.GetState().IsKeyDown(Keys.E))
 | 
			
		||||
            cameraBehaviour.BehaviourController.GameObject.Transform.Rotation -= gameTime.ElapsedGameTime.Nanoseconds * 0.000025f;
 | 
			
		||||
 | 
			
		||||
        if (Keyboard.GetState().IsKeyDown(Keys.N))
 | 
			
		||||
        {
 | 
			
		||||
            seconds = 70f;
 | 
			
		||||
            while (physicsTimer + 0.01f < seconds)
 | 
			
		||||
            {
 | 
			
		||||
                physicsTimer += 0.01f;
 | 
			
		||||
                engine.Step(.01f);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if (Keyboard.GetState().IsKeyDown(Keys.M))
 | 
			
		||||
        {
 | 
			
		||||
            seconds = 0f;
 | 
			
		||||
            while (physicsTimer - 0.01f > seconds)
 | 
			
		||||
            {
 | 
			
		||||
                physicsTimer -= 0.01f;
 | 
			
		||||
                engine.Step(-.01f);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if (Keyboard.GetState().IsKeyDown(Keys.Space))
 | 
			
		||||
        {
 | 
			
		||||
            seconds += gameTime.ElapsedGameTime.Milliseconds * .005f;
 | 
			
		||||
            while (physicsTimer + 0.01f < seconds)
 | 
			
		||||
            {
 | 
			
		||||
                Console.WriteLine($"Physics Timer: {physicsTimer}");
 | 
			
		||||
                physicsTimer += 0.01f;
 | 
			
		||||
                engine.Step(.01f);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if (Keyboard.GetState().IsKeyDown(Keys.B))
 | 
			
		||||
        {
 | 
			
		||||
            seconds -= gameTime.ElapsedGameTime.Milliseconds * .005f;
 | 
			
		||||
            while (physicsTimer - 0.01f > seconds)
 | 
			
		||||
            {
 | 
			
		||||
                Console.WriteLine($"Physics Timer: {physicsTimer}");
 | 
			
		||||
                physicsTimer -= 0.01f;
 | 
			
		||||
                engine.Step(-.01f);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        // while (physicsTimer + 0.01f < gameTime.TotalGameTime.TotalMilliseconds * .001f)//seconds)
 | 
			
		||||
        // {
 | 
			
		||||
        //     Console.WriteLine($"Physics Timer: {physicsTimer}");
 | 
			
		||||
        //     physicsTimer += 0.01f;
 | 
			
		||||
        //     engine.Step(.01f);
 | 
			
		||||
        // }
 | 
			
		||||
        gameManager.Update(gameTime.ToEngineTime());
 | 
			
		||||
        base.Update(gameTime);
 | 
			
		||||
    }
 | 
			
		||||
    static float physicsTimer = 0f;
 | 
			
		||||
    static float seconds = 0f;
 | 
			
		||||
 | 
			
		||||
    protected override void Draw(GameTime gameTime)
 | 
			
		||||
    {
 | 
			
		||||
        GraphicsDevice.Clear(new Color() { R = 32, G = 32, B = 32 });
 | 
			
		||||
 | 
			
		||||
        // gameManager.Camera.Position = gameObjectBall.Transform.Position;
 | 
			
		||||
        // Console.WriteLine($"Pos: {gameManager.Camera.Position}");
 | 
			
		||||
 | 
			
		||||
        // TODO: Add your drawing code here
 | 
			
		||||
        gameManager.PreDraw();
 | 
			
		||||
        gameManager.Camera.Update();
 | 
			
		||||
 | 
			
		||||
        _spriteBatch.Begin(SpriteSortMode.Deferred, transformMatrix: cameraBehaviour.MatrixTransform);
 | 
			
		||||
        foreach (IGameObject gameObject in gameManager)
 | 
			
		||||
        {
 | 
			
		||||
            if (!gameObject.BehaviourController.TryGetBehaviour(out IDisplayable? displayable))
 | 
			
		||||
                continue;
 | 
			
		||||
 | 
			
		||||
            displayable.Draw(_spriteBatch);
 | 
			
		||||
        }
 | 
			
		||||
        _spriteBatch.End();
 | 
			
		||||
 | 
			
		||||
        base.Draw(gameTime);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,26 +0,0 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Core.Abstract;
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// Indicates the object is an <see cref="IAssignable"/> with an assignable <see cref="ISprite"/> field.
 | 
			
		||||
/// </summary>
 | 
			
		||||
public interface IAssignableSprite : IAssignable
 | 
			
		||||
{
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Callback triggered when the <see cref="ISprite"/> value has has been assigned a new value.
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    Action<IAssignableSprite>? OnSpriteAssigned { get; set; }
 | 
			
		||||
 | 
			
		||||
    /// <inheritdoc cref="ISprite" />
 | 
			
		||||
    ISprite Sprite { get; }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Assign a value to the <see cref="ISprite"/> field of this object
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    /// <param name="sprite">New <see cref="ISprite"/> to assign.</param>
 | 
			
		||||
    /// <returns> 
 | 
			
		||||
    /// <see cref="true"/>, if the value given assigned successfully assigned, <see cref="false"/> if not.
 | 
			
		||||
    /// </returns>
 | 
			
		||||
    bool Assign(ISprite sprite);
 | 
			
		||||
}
 | 
			
		||||
@@ -1,13 +0,0 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
using Microsoft.Xna.Framework.Graphics;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Core.Abstract;
 | 
			
		||||
 | 
			
		||||
// TODO Probably gonna have to rethink this
 | 
			
		||||
public interface ISprite
 | 
			
		||||
{
 | 
			
		||||
    Action<ISprite>? OnTextureChanged { get; set; }
 | 
			
		||||
 | 
			
		||||
    Texture2D Texture2D { get; set; }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,27 +0,0 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
using Microsoft.Xna.Framework.Graphics;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core.Abstract;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
public class Sprite : ISprite
 | 
			
		||||
{
 | 
			
		||||
    public Action<ISprite>? OnTextureChanged { get; set; }
 | 
			
		||||
 | 
			
		||||
    private Texture2D _texture = null!;
 | 
			
		||||
 | 
			
		||||
    public Texture2D Texture2D
 | 
			
		||||
    {
 | 
			
		||||
        get => _texture;
 | 
			
		||||
        set
 | 
			
		||||
        {
 | 
			
		||||
            if (_texture == value)
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            _texture = value;
 | 
			
		||||
            OnTextureChanged?.Invoke(this);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,8 +0,0 @@
 | 
			
		||||
using Microsoft.Xna.Framework.Graphics;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Core.Abstract;
 | 
			
		||||
 | 
			
		||||
public interface IDisplayable
 | 
			
		||||
{
 | 
			
		||||
    public void Draw(SpriteBatch spriteBatch);
 | 
			
		||||
}
 | 
			
		||||
@@ -1,20 +0,0 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
using Microsoft.Xna.Framework;
 | 
			
		||||
using Microsoft.Xna.Framework.Graphics;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core.Abstract;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Graphics.TwoDimensional.Abstract;
 | 
			
		||||
public interface IDisplayableSprite : IDisplayable, IAssignableSprite
 | 
			
		||||
{
 | 
			
		||||
    Action<IDisplayableSprite>? OnSpriteEffectsChanged { get; set; }
 | 
			
		||||
    Action<IDisplayableSprite>? OnOriginChanged { get; set; }
 | 
			
		||||
    Action<IDisplayableSprite>? OnColorChanged { get; set; }
 | 
			
		||||
    Action<IDisplayableSprite>? OnDepthChanged { get; set; }
 | 
			
		||||
 | 
			
		||||
    SpriteEffects SpriteEffects { get; set; }
 | 
			
		||||
    Vector2 Origin { get; set; }
 | 
			
		||||
    Color Color { get; set; }
 | 
			
		||||
    float Depth { get; set; }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,117 +0,0 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
using Microsoft.Xna.Framework;
 | 
			
		||||
using Microsoft.Xna.Framework.Graphics;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
using Syntriax.Engine.Core.Abstract;
 | 
			
		||||
using Syntriax.Engine.Graphics.TwoDimensional.Abstract;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Graphics.TwoDimensional;
 | 
			
		||||
 | 
			
		||||
public class DisplayableSpriteBehaviour : Behaviour, IDisplayableSprite, IAssignableSprite
 | 
			
		||||
{
 | 
			
		||||
    public Action<IAssignableSprite>? OnSpriteAssigned { get; set; } = null;
 | 
			
		||||
    public Action<IDisplayableSprite>? OnSpriteEffectsChanged { get; set; } = null;
 | 
			
		||||
    public Action<IDisplayableSprite>? OnOriginChanged { get; set; } = null;
 | 
			
		||||
    public Action<IDisplayableSprite>? OnColorChanged { get; set; } = null;
 | 
			
		||||
    public Action<IDisplayableSprite>? OnDepthChanged { get; set; } = null;
 | 
			
		||||
 | 
			
		||||
    private ISprite _sprite = null!;
 | 
			
		||||
    private Color _color = Color.White;
 | 
			
		||||
    private float _depth = 0f;
 | 
			
		||||
    private SpriteEffects _spriteEffects = SpriteEffects.None;
 | 
			
		||||
    private Vector2 _origin = Vector2.One * .5f;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    public ISprite Sprite => _sprite;
 | 
			
		||||
 | 
			
		||||
    public SpriteEffects SpriteEffects
 | 
			
		||||
    {
 | 
			
		||||
        get => _spriteEffects;
 | 
			
		||||
        set
 | 
			
		||||
        {
 | 
			
		||||
            if (_spriteEffects == value)
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            _spriteEffects = value;
 | 
			
		||||
            OnSpriteEffectsChanged?.Invoke(this);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Vector2 Origin
 | 
			
		||||
    {
 | 
			
		||||
        get => _origin;
 | 
			
		||||
        set
 | 
			
		||||
        {
 | 
			
		||||
            if (_origin == value)
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            _origin = value;
 | 
			
		||||
            OnOriginChanged?.Invoke(this);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Color Color
 | 
			
		||||
    {
 | 
			
		||||
        get => _color;
 | 
			
		||||
        set
 | 
			
		||||
        {
 | 
			
		||||
            if (_color == value)
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            _color = value;
 | 
			
		||||
            OnColorChanged?.Invoke(this);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public float Depth
 | 
			
		||||
    {
 | 
			
		||||
        get => _depth;
 | 
			
		||||
        set
 | 
			
		||||
        {
 | 
			
		||||
            if (_depth == value)
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            _depth = value;
 | 
			
		||||
            OnDepthChanged?.Invoke(this);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void Draw(SpriteBatch spriteBatch)
 | 
			
		||||
    {
 | 
			
		||||
        if (!BehaviourController.GameObject.StateEnable.Enabled || !StateEnable.Enabled)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        ITransform transform = BehaviourController.GameObject.Transform;
 | 
			
		||||
        Vector2D position = transform.Position;
 | 
			
		||||
        Vector2D scale = transform.Scale;
 | 
			
		||||
 | 
			
		||||
        Rectangle rectangle = new((int)position.X, -(int)position.Y, (int)(Sprite.Texture2D.Width * scale.X), (int)(Sprite.Texture2D.Height * scale.Y));
 | 
			
		||||
 | 
			
		||||
        spriteBatch.Draw(Sprite.Texture2D, rectangle, null, Color, transform.Rotation, new Vector2(Sprite.Texture2D.Width, Sprite.Texture2D.Height) * Origin, SpriteEffects, Depth);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public bool Assign(ISprite sprite)
 | 
			
		||||
    {
 | 
			
		||||
        _sprite = sprite;
 | 
			
		||||
        OnSpriteAssigned?.Invoke(this);
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public DisplayableSpriteBehaviour() => OnUnassigned += OnUnassign;
 | 
			
		||||
    public DisplayableSpriteBehaviour(
 | 
			
		||||
        Color? color = null,
 | 
			
		||||
        float? depth = null,
 | 
			
		||||
        SpriteEffects? spriteEffects = null,
 | 
			
		||||
        Vector2? origin = null)
 | 
			
		||||
    {
 | 
			
		||||
        OnUnassigned += OnUnassign;
 | 
			
		||||
 | 
			
		||||
        _color = color ?? _color;
 | 
			
		||||
        _depth = depth ?? _depth;
 | 
			
		||||
        _spriteEffects = spriteEffects ?? _spriteEffects;
 | 
			
		||||
        _origin = origin ?? _origin;
 | 
			
		||||
    }
 | 
			
		||||
    private void OnUnassign(IAssignable assignable) => _sprite = null!;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								Game/Icon.bmp
									
									
									
									
									
								
							
							
						
						| 
		 Before Width: | Height: | Size: 256 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								Game/Icon.ico
									
									
									
									
									
								
							
							
						
						| 
		 Before Width: | Height: | Size: 144 KiB  | 
@@ -1,19 +0,0 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
using Syntriax.Engine.Core.Abstract;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Physics2D.Abstract;
 | 
			
		||||
 | 
			
		||||
public interface ICollider2D : IBehaviour, IAssignableTransform
 | 
			
		||||
{
 | 
			
		||||
    Action<ICollider2D, ICollider2D>? OnCollisionPreResolve { get; set; }
 | 
			
		||||
 | 
			
		||||
    IRigidBody2D? RigidBody2D { get; }
 | 
			
		||||
 | 
			
		||||
    IList<Vector2D> Vertices { get; }
 | 
			
		||||
 | 
			
		||||
    bool CheckCollision(Vector2D point);
 | 
			
		||||
    void Recalculate();
 | 
			
		||||
}
 | 
			
		||||
@@ -1,6 +0,0 @@
 | 
			
		||||
namespace Syntriax.Engine.Physics2D.Abstract;
 | 
			
		||||
 | 
			
		||||
public interface ICollisionResolver2D
 | 
			
		||||
{
 | 
			
		||||
    void ResolveCollision(ICollider2D colliderA, ICollider2D colliderB);
 | 
			
		||||
}
 | 
			
		||||
@@ -1,11 +0,0 @@
 | 
			
		||||
namespace Syntriax.Engine.Physics2D.Abstract;
 | 
			
		||||
 | 
			
		||||
public interface IPhysicsEngine2D
 | 
			
		||||
{
 | 
			
		||||
    int IterationCount { get; set; }
 | 
			
		||||
 | 
			
		||||
    void AddRigidBody(IRigidBody2D rigidBody);
 | 
			
		||||
    void RemoveRigidBody(IRigidBody2D rigidBody);
 | 
			
		||||
 | 
			
		||||
    void Step(float deltaTime);
 | 
			
		||||
}
 | 
			
		||||
@@ -1,7 +0,0 @@
 | 
			
		||||
namespace Syntriax.Engine.Physics2D.Abstract;
 | 
			
		||||
 | 
			
		||||
public interface IPhysicsMaterial2D
 | 
			
		||||
{
 | 
			
		||||
    float Friction { get; }
 | 
			
		||||
    float Restitution { get; }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,14 +0,0 @@
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
using Syntriax.Engine.Core.Abstract;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Physics2D.Abstract;
 | 
			
		||||
 | 
			
		||||
public interface IRigidBody2D : IBehaviour, IAssignableTransform
 | 
			
		||||
{
 | 
			
		||||
    IPhysicsMaterial2D Material { get; set; }
 | 
			
		||||
 | 
			
		||||
    Vector2D Velocity { get; set; }
 | 
			
		||||
    float AngularVelocity { get; set; }
 | 
			
		||||
 | 
			
		||||
    float Mass { get; set; }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,67 +0,0 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
using Syntriax.Engine.Core.Abstract;
 | 
			
		||||
using Syntriax.Engine.Physics2D.Abstract;
 | 
			
		||||
using Syntriax.Engine.Physics2D.Primitives;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Physics2D;
 | 
			
		||||
 | 
			
		||||
public class Collider2DAABBBehaviour : BehaviourOverride, ICollider2D
 | 
			
		||||
{
 | 
			
		||||
    public AABB AABBLocal { get; set; } = null!;
 | 
			
		||||
    public AABB AABBWorld { get; private set; } = null!;
 | 
			
		||||
 | 
			
		||||
    private IRigidBody2D? _rigidBody2D = null;
 | 
			
		||||
    private List<Vector2D> _vertices = new List<Vector2D>(4);
 | 
			
		||||
 | 
			
		||||
    public IRigidBody2D? RigidBody2D
 | 
			
		||||
    {
 | 
			
		||||
        get
 | 
			
		||||
        {
 | 
			
		||||
            if (_rigidBody2D is null)
 | 
			
		||||
                BehaviourController.TryGetBehaviour(out _rigidBody2D);
 | 
			
		||||
 | 
			
		||||
            return _rigidBody2D;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Action<ICollider2D, ICollider2D>? OnCollisionPreResolve { get; set; } = null;
 | 
			
		||||
 | 
			
		||||
    public Action<IAssignableTransform>? OnTransformAssigned { get => GameObject.OnTransformAssigned; set => GameObject.OnTransformAssigned = value; }
 | 
			
		||||
    ITransform IAssignableTransform.Transform => Transform;
 | 
			
		||||
    public bool Assign(ITransform transform) => GameObject.Assign(transform);
 | 
			
		||||
 | 
			
		||||
    public IList<Vector2D> Vertices => _vertices;
 | 
			
		||||
 | 
			
		||||
    public bool CheckCollision(Vector2D point)
 | 
			
		||||
    {
 | 
			
		||||
        return AABBWorld.Overlaps(point);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void Recalculate()
 | 
			
		||||
    {
 | 
			
		||||
        AABBWorld = new AABB(
 | 
			
		||||
            AABBLocal.LowerBoundary.Scale(Transform.Scale) + Transform.Position,
 | 
			
		||||
            AABBLocal.UpperBoundary.Scale(Transform.Scale) + Transform.Position
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        Vertices.Clear();
 | 
			
		||||
        Vertices.Add(AABBWorld.LowerBoundary);
 | 
			
		||||
        Vertices.Add(new Vector2D(AABBWorld.LowerBoundary.X, AABBWorld.UpperBoundary.Y));
 | 
			
		||||
        Vertices.Add(AABBWorld.UpperBoundary);
 | 
			
		||||
        Vertices.Add(new Vector2D(AABBWorld.UpperBoundary.X, AABBWorld.LowerBoundary.Y));
 | 
			
		||||
    }
 | 
			
		||||
    public Collider2DAABBBehaviour(Vector2D lowerBoundary, Vector2D upperBoundary)
 | 
			
		||||
    {
 | 
			
		||||
        AABBLocal = new AABB(lowerBoundary, upperBoundary);
 | 
			
		||||
        AABBWorld = new AABB(lowerBoundary, upperBoundary);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Collider2DAABBBehaviour()
 | 
			
		||||
    {
 | 
			
		||||
        AABBLocal = new(Vector2D.Zero, Vector2D.Zero);
 | 
			
		||||
        AABBWorld = new(Vector2D.Zero, Vector2D.Zero);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,9 +0,0 @@
 | 
			
		||||
using Microsoft.Xna.Framework;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Physics2D;
 | 
			
		||||
 | 
			
		||||
public record CollisionInformation
 | 
			
		||||
(
 | 
			
		||||
    Vector2 Normal,
 | 
			
		||||
    Vector2 ContactPosition
 | 
			
		||||
);
 | 
			
		||||
@@ -1,75 +0,0 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
using Syntriax.Engine.Core.Abstract;
 | 
			
		||||
using Syntriax.Engine.Physics2D.Abstract;
 | 
			
		||||
using Syntriax.Engine.Physics2D.Primitives;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Physics2D;
 | 
			
		||||
 | 
			
		||||
public class PhysicsEngine2D : IPhysicsEngine2D
 | 
			
		||||
{
 | 
			
		||||
    private List<IRigidBody2D> rigidBodies = new List<IRigidBody2D>(32);
 | 
			
		||||
    private List<ICollider2D> colliders = new List<ICollider2D>(64);
 | 
			
		||||
 | 
			
		||||
    private int _iterationCount = 1;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    public int IterationCount { get => _iterationCount; set => _iterationCount = value < 1 ? 1 : value; }
 | 
			
		||||
 | 
			
		||||
    public void AddRigidBody(IRigidBody2D rigidBody)
 | 
			
		||||
    {
 | 
			
		||||
        if (rigidBodies.Contains(rigidBody))
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        rigidBodies.Add(rigidBody);
 | 
			
		||||
 | 
			
		||||
        foreach (var collider2D in rigidBody.BehaviourController.GetBehaviours<ICollider2D>())
 | 
			
		||||
            colliders.Add(collider2D);
 | 
			
		||||
 | 
			
		||||
        rigidBody.BehaviourController.OnBehaviourAdded += OnBehaviourAdded;
 | 
			
		||||
        rigidBody.BehaviourController.OnBehaviourRemoved += OnBehaviourRemoved;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void RemoveRigidBody(IRigidBody2D rigidBody)
 | 
			
		||||
    {
 | 
			
		||||
        rigidBodies.Remove(rigidBody);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void Step(float deltaTime)
 | 
			
		||||
    {
 | 
			
		||||
        float intervalDeltaTime = deltaTime / IterationCount;
 | 
			
		||||
 | 
			
		||||
        for (int iterationIndex = 0; iterationIndex < IterationCount; iterationIndex++)
 | 
			
		||||
        {
 | 
			
		||||
            foreach (var rigidBody in rigidBodies)
 | 
			
		||||
                StepRigidBody(rigidBody, intervalDeltaTime);
 | 
			
		||||
 | 
			
		||||
            foreach (var collider in colliders)
 | 
			
		||||
                collider.Recalculate();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static void StepRigidBody(IRigidBody2D rigidBody, float intervalDeltaTime)
 | 
			
		||||
    {
 | 
			
		||||
        rigidBody.Transform.Position += rigidBody.Velocity * intervalDeltaTime;
 | 
			
		||||
        rigidBody.Transform.Rotation += rigidBody.AngularVelocity * intervalDeltaTime;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void OnBehaviourAdded(IBehaviourController controller, IBehaviour behaviour)
 | 
			
		||||
    {
 | 
			
		||||
        if (behaviour is not ICollider2D collider2D)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        colliders.Add(collider2D);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void OnBehaviourRemoved(IBehaviourController controller, IBehaviour behaviour)
 | 
			
		||||
    {
 | 
			
		||||
        if (behaviour is not ICollider2D collider2D)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        colliders.Remove(collider2D);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,5 +0,0 @@
 | 
			
		||||
using Syntriax.Engine.Physics2D.Abstract;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Physics2D;
 | 
			
		||||
 | 
			
		||||
public record PhysicsMaterial2D(float Friction, float Restitution) : IPhysicsMaterial2D { }
 | 
			
		||||
@@ -1,6 +0,0 @@
 | 
			
		||||
namespace Syntriax.Engine.Physics2D;
 | 
			
		||||
 | 
			
		||||
public record PhysicsMaterial2DDefault : PhysicsMaterial2D
 | 
			
		||||
{
 | 
			
		||||
    public PhysicsMaterial2DDefault() : base(.1f, .1f) { }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,118 +0,0 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
 | 
			
		||||
using Microsoft.Xna.Framework;
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
using Syntriax.Engine.Physics2D.Primitives;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Physics2D;
 | 
			
		||||
 | 
			
		||||
public static class PhysicsMath
 | 
			
		||||
{
 | 
			
		||||
    public static Vector2D Scale(this Vector2D original, Vector2D scale)
 | 
			
		||||
        => new Vector2D(original.X * scale.X, original.Y * scale.Y);
 | 
			
		||||
 | 
			
		||||
    public static Triangle ToSuperTriangle(this IList<Vector2D> vertices)
 | 
			
		||||
    {
 | 
			
		||||
        float minX = float.MaxValue, minY = float.MaxValue;
 | 
			
		||||
        float maxX = float.MinValue, maxY = float.MinValue;
 | 
			
		||||
 | 
			
		||||
        foreach (Vector2D point in vertices)
 | 
			
		||||
        {
 | 
			
		||||
            minX = MathF.Min(minX, point.X);
 | 
			
		||||
            minY = MathF.Min(minY, point.Y);
 | 
			
		||||
            maxX = MathF.Max(maxX, point.X);
 | 
			
		||||
            maxY = MathF.Max(maxY, point.Y);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        float dx = maxX - minX;
 | 
			
		||||
        float dy = maxY - minY;
 | 
			
		||||
        float deltaMax = MathF.Max(dx, dy);
 | 
			
		||||
        float midX = (minX + maxX) / 2;
 | 
			
		||||
        float midY = (minY + maxY) / 2;
 | 
			
		||||
 | 
			
		||||
        Vector2D p1 = new Vector2D((float)midX - 20f * (float)deltaMax, (float)midY - (float)deltaMax);
 | 
			
		||||
        Vector2D p2 = new Vector2D((float)midX, (float)midY + 20 * (float)deltaMax);
 | 
			
		||||
        Vector2D p3 = new Vector2D((float)midX + 20 * (float)deltaMax, (float)midY - (float)deltaMax);
 | 
			
		||||
 | 
			
		||||
        return new Triangle(p1, p2, p3);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static IList<Line> ToLines(this IList<Vector2D> vertices)
 | 
			
		||||
    {
 | 
			
		||||
        List<Line> lines = new List<Line>(vertices.Count - 1);
 | 
			
		||||
        ToLines(vertices, lines);
 | 
			
		||||
        return lines;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static void ToLines(this IList<Vector2D> vertices, IList<Line> lines)
 | 
			
		||||
    {
 | 
			
		||||
        lines.Clear();
 | 
			
		||||
        for (int i = 0; i < vertices.Count - 1; i++)
 | 
			
		||||
            lines.Add(new(vertices[i], vertices[i + 1]));
 | 
			
		||||
        lines.Add(new(vertices[^1], vertices[0]));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static bool LaysOn(this Vector2D point, Line line)
 | 
			
		||||
        => line.Resolve(point.X).ApproximatelyEquals(point);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    // Given three collinear points p, q, r, the function checks if 
 | 
			
		||||
    // point q lies on line segment 'pr' 
 | 
			
		||||
    public static bool OnSegment(Vector2D p, Vector2D q, Vector2D r)
 | 
			
		||||
    {
 | 
			
		||||
        if (q.X <= MathF.Max(p.X, r.X) && q.X >= MathF.Min(p.X, r.X) &&
 | 
			
		||||
            q.Y <= MathF.Max(p.Y, r.Y) && q.Y >= MathF.Min(p.Y, r.Y))
 | 
			
		||||
            return true;
 | 
			
		||||
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // To find orientation of ordered triplet (p, q, r). 
 | 
			
		||||
    // The function returns following values 
 | 
			
		||||
    // 0 --> p, q and r are collinear 
 | 
			
		||||
    // 1 --> Clockwise 
 | 
			
		||||
    // 2 --> Counterclockwise 
 | 
			
		||||
    public static int Orientation(Vector2D p, Vector2D q, Vector2D r)
 | 
			
		||||
    {
 | 
			
		||||
        // See https://www.geeksforgeeks.org/orientation-3-ordered-points/ 
 | 
			
		||||
        // for details of below formula. 
 | 
			
		||||
        float val = (q.Y - p.Y) * (r.X - q.X) -
 | 
			
		||||
                (q.X - p.X) * (r.Y - q.Y);
 | 
			
		||||
 | 
			
		||||
        if (val == 0) return 0; // collinear 
 | 
			
		||||
 | 
			
		||||
        return (val > 0) ? 1 : 2; // clock or counterclock wise 
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static float IntersectionParameterT(Vector2D p0, Vector2D p1, Vector2D q0, Vector2D q1)
 | 
			
		||||
        => ((q0.X - p0.X) * (p1.Y - p0.Y) - (q0.Y - p0.Y) * (p1.X - p0.X)) /
 | 
			
		||||
            ((q1.Y - q0.Y) * (p1.X - p0.X) - (q1.X - q0.X) * (p1.Y - p0.Y));
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    public static bool ApproximatelyEquals(this float a, float b)
 | 
			
		||||
        => ApproximatelyEquals(a, b, float.Epsilon);
 | 
			
		||||
    public static bool ApproximatelyEquals(this Vector2 a, Vector2 b)
 | 
			
		||||
        => ApproximatelyEquals(a, b, float.Epsilon);
 | 
			
		||||
    public static bool ApproximatelyEquals(this Vector2 a, Vector2 b, float epsilon)
 | 
			
		||||
        => ApproximatelyEquals(a.X, b.X, epsilon) && ApproximatelyEquals(a.Y, b.Y, epsilon);
 | 
			
		||||
    public static bool ApproximatelyEquals(this Vector2D a, Vector2D b)
 | 
			
		||||
        => ApproximatelyEquals(a, b, float.Epsilon);
 | 
			
		||||
    public static bool ApproximatelyEquals(this Vector2D a, Vector2D b, float epsilon)
 | 
			
		||||
        => ApproximatelyEquals(a.X, b.X, epsilon) && ApproximatelyEquals(a.Y, b.Y, epsilon);
 | 
			
		||||
    public static bool ApproximatelyEquals(this float a, float b, float epsilon)
 | 
			
		||||
    {
 | 
			
		||||
        if (a == b)
 | 
			
		||||
            return true;
 | 
			
		||||
 | 
			
		||||
        const float floatNormal = (1 << 23) * float.Epsilon;
 | 
			
		||||
        float absA = MathF.Abs(a);
 | 
			
		||||
        float absB = MathF.Abs(b);
 | 
			
		||||
        float diff = MathF.Abs(a - b);
 | 
			
		||||
 | 
			
		||||
        if (a == 0.0f || b == 0.0f || diff < floatNormal)
 | 
			
		||||
            return diff < (epsilon * floatNormal);
 | 
			
		||||
 | 
			
		||||
        return diff / MathF.Min(absA + absB, float.MaxValue) < epsilon;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,17 +0,0 @@
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Physics2D.Primitives;
 | 
			
		||||
 | 
			
		||||
public record AABB(Vector2D LowerBoundary, Vector2D UpperBoundary)
 | 
			
		||||
{
 | 
			
		||||
    public bool Overlaps(Vector2D point)
 | 
			
		||||
        => point.X >= LowerBoundary.X && point.X <= UpperBoundary.X &&
 | 
			
		||||
            point.Y >= LowerBoundary.Y && point.Y <= UpperBoundary.Y;
 | 
			
		||||
 | 
			
		||||
    public bool Overlaps(AABB other)
 | 
			
		||||
        => LowerBoundary.X <= other.UpperBoundary.X && UpperBoundary.X >= other.LowerBoundary.X &&
 | 
			
		||||
            LowerBoundary.Y <= other.UpperBoundary.Y && UpperBoundary.Y >= other.LowerBoundary.Y;
 | 
			
		||||
 | 
			
		||||
    public bool ApproximatelyEquals(AABB other)
 | 
			
		||||
        => LowerBoundary.ApproximatelyEquals(other.LowerBoundary) && UpperBoundary.ApproximatelyEquals(other.UpperBoundary);
 | 
			
		||||
}
 | 
			
		||||
@@ -1,18 +0,0 @@
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Physics2D.Primitives;
 | 
			
		||||
 | 
			
		||||
public record Circle(Vector2D Position, float Radius)
 | 
			
		||||
{
 | 
			
		||||
    public bool Intersects(Circle other)
 | 
			
		||||
    {
 | 
			
		||||
        float distanceSquared = (Position - other.Position).LengthSquared();
 | 
			
		||||
        float radiusSumSquared = Radius * Radius + other.Radius * other.Radius;
 | 
			
		||||
 | 
			
		||||
        return distanceSquared < radiusSumSquared;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public bool Overlaps(Vector2D point) => (Position - point).LengthSquared() <= Radius * Radius;
 | 
			
		||||
    public bool ApproximatelyEquals(Circle other)
 | 
			
		||||
        => Position.ApproximatelyEquals(other.Position) && Radius.ApproximatelyEquals(other.Radius);
 | 
			
		||||
}
 | 
			
		||||
@@ -1,146 +0,0 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Diagnostics.CodeAnalysis;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Physics2D.Primitives;
 | 
			
		||||
 | 
			
		||||
public record Line(Vector2D From, Vector2D To)
 | 
			
		||||
{
 | 
			
		||||
    public Line Reversed => new(To, From);
 | 
			
		||||
    public Vector2D Direction => Vector2D.Normalize(To - From);
 | 
			
		||||
    public float Length => (From - To).Length();
 | 
			
		||||
    public float LengthSquared => (From - To).LengthSquared();
 | 
			
		||||
 | 
			
		||||
    public LineEquation LineEquation
 | 
			
		||||
    {
 | 
			
		||||
        get
 | 
			
		||||
        {
 | 
			
		||||
            Vector2D slopeVector = To - From;
 | 
			
		||||
            float slope = slopeVector.Y / slopeVector.X;
 | 
			
		||||
 | 
			
		||||
            float yOffset = From.Y - (slope * From.X);
 | 
			
		||||
 | 
			
		||||
            return new LineEquation(slope, yOffset);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public bool Intersects(Vector2D point)
 | 
			
		||||
        => Resolve(point.X).ApproximatelyEquals(point);
 | 
			
		||||
 | 
			
		||||
    public float GetT(Vector2D point)
 | 
			
		||||
    {
 | 
			
		||||
        float fromX = MathF.Abs(From.X);
 | 
			
		||||
        float toX = MathF.Abs(To.X);
 | 
			
		||||
        float pointX = MathF.Abs(point.X);
 | 
			
		||||
 | 
			
		||||
        float min = MathF.Min(fromX, toX);
 | 
			
		||||
        float max = MathF.Max(fromX, toX) - min;
 | 
			
		||||
 | 
			
		||||
        pointX -= min;
 | 
			
		||||
 | 
			
		||||
        float t = pointX / max;
 | 
			
		||||
 | 
			
		||||
        // FIXME
 | 
			
		||||
        // I don't even know, apparently whatever I wrote up there doesn't take into account of the direction of the line
 | 
			
		||||
        // Which... I can see how, but I am also not sure how I can make it take into account. Or actually I'm for some reason
 | 
			
		||||
        // too unmotivated to find a solution. Future me, find a better way if possible, please.
 | 
			
		||||
        if (!Lerp(t).ApproximatelyEquals(point))
 | 
			
		||||
            return 1f - t;
 | 
			
		||||
        return t;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public bool Exist(List<Vector2D> vertices)
 | 
			
		||||
    {
 | 
			
		||||
        for (int i = 0; i < vertices.Count - 1; i++)
 | 
			
		||||
        {
 | 
			
		||||
            Vector2D vertexCurrent = vertices[i];
 | 
			
		||||
            Vector2D vertexNext = vertices[i];
 | 
			
		||||
            if (From == vertexCurrent && To == vertexNext) return true;
 | 
			
		||||
            if (From == vertexNext && To == vertexCurrent) return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Vector2D vertexFirst = vertices[0];
 | 
			
		||||
        Vector2D vertexLast = vertices[^1];
 | 
			
		||||
        if (From == vertexFirst && To == vertexLast) return true;
 | 
			
		||||
        if (From == vertexLast && To == vertexFirst) return true;
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public float IntersectionParameterT(Line other)
 | 
			
		||||
    {
 | 
			
		||||
        float numerator = (From.X - other.From.X) * (other.From.Y - other.To.Y) - (From.Y - other.From.Y) * (other.From.X - other.To.X);
 | 
			
		||||
        float denominator = (From.X - To.X) * (other.From.Y - other.To.Y) - (From.Y - To.Y) * (other.From.X - other.To.X);
 | 
			
		||||
 | 
			
		||||
        // Lines are parallel
 | 
			
		||||
        if (denominator == 0)
 | 
			
		||||
            return float.NaN;
 | 
			
		||||
 | 
			
		||||
        return numerator / denominator;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Vector2D Lerp(float t)
 | 
			
		||||
        => new Vector2D(
 | 
			
		||||
            From.X + (To.X - From.X) * t,
 | 
			
		||||
            From.Y + (To.Y - From.Y) * t
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
    public Vector2D Resolve(float x)
 | 
			
		||||
        => new Vector2D(x, LineEquation.Resolve(x));
 | 
			
		||||
 | 
			
		||||
    public Vector2D ClosestPointTo(Vector2D point)
 | 
			
		||||
    {
 | 
			
		||||
        // Convert edge points to vectors
 | 
			
		||||
        var edgeVector = new Vector2D(To.X - From.X, To.Y - From.Y);
 | 
			
		||||
        var pointVector = new Vector2D(point.X - From.X, point.Y - From.Y);
 | 
			
		||||
 | 
			
		||||
        // Calculate the projection of pointVector onto edgeVector
 | 
			
		||||
        float t = (pointVector.X * edgeVector.X + pointVector.Y * edgeVector.Y) / (edgeVector.X * edgeVector.X + edgeVector.Y * edgeVector.Y);
 | 
			
		||||
 | 
			
		||||
        // Clamp t to the range [0, 1] to ensure the closest point is on the edge
 | 
			
		||||
        t = MathF.Max(0, MathF.Min(1, t));
 | 
			
		||||
 | 
			
		||||
        // Calculate the closest point on the edge
 | 
			
		||||
        float closestX = From.X + t * edgeVector.X;
 | 
			
		||||
        float closestY = From.Y + t * edgeVector.Y;
 | 
			
		||||
 | 
			
		||||
        return new Vector2D((float)closestX, (float)closestY);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Vector2D IntersectionPoint(Line other)
 | 
			
		||||
        => Vector2D.Lerp(From, To, IntersectionParameterT(other));
 | 
			
		||||
 | 
			
		||||
    public bool Intersects(Line other)
 | 
			
		||||
    {
 | 
			
		||||
        int o1 = PhysicsMath.Orientation(From, To, other.From);
 | 
			
		||||
        int o2 = PhysicsMath.Orientation(From, To, other.To);
 | 
			
		||||
        int o3 = PhysicsMath.Orientation(other.From, other.To, From);
 | 
			
		||||
        int o4 = PhysicsMath.Orientation(other.From, other.To, To);
 | 
			
		||||
 | 
			
		||||
        if (o1 != o2 && o3 != o4)
 | 
			
		||||
            return true;
 | 
			
		||||
 | 
			
		||||
        if (o1 == 0 && PhysicsMath.OnSegment(From, other.From, To)) return true;
 | 
			
		||||
        if (o2 == 0 && PhysicsMath.OnSegment(From, other.To, To)) return true;
 | 
			
		||||
        if (o3 == 0 && PhysicsMath.OnSegment(other.From, From, other.To)) return true;
 | 
			
		||||
        if (o4 == 0 && PhysicsMath.OnSegment(other.From, To, other.To)) return true;
 | 
			
		||||
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public bool Intersects(Line other, [NotNullWhen(returnValue: true)] out Vector2D? point)
 | 
			
		||||
    {
 | 
			
		||||
        point = null;
 | 
			
		||||
 | 
			
		||||
        bool result = Intersects(other);
 | 
			
		||||
 | 
			
		||||
        if (result)
 | 
			
		||||
            point = IntersectionPoint(other);
 | 
			
		||||
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public bool ApproximatelyEquals(Line other)
 | 
			
		||||
        => From.ApproximatelyEquals(other.From) && To.ApproximatelyEquals(other.To);
 | 
			
		||||
}
 | 
			
		||||
@@ -1,8 +0,0 @@
 | 
			
		||||
namespace Syntriax.Engine.Physics2D.Primitives;
 | 
			
		||||
 | 
			
		||||
public record LineEquation(float Slope, float OffsetY)
 | 
			
		||||
{
 | 
			
		||||
    public float Resolve(float x) => Slope * x + OffsetY; // y = mx + b
 | 
			
		||||
    public bool ApproximatelyEquals(LineEquation other)
 | 
			
		||||
        => Slope.ApproximatelyEquals(other.Slope) && OffsetY.ApproximatelyEquals(other.OffsetY);
 | 
			
		||||
}
 | 
			
		||||
@@ -1,9 +0,0 @@
 | 
			
		||||
namespace Syntriax.Engine.Physics2D.Primitives;
 | 
			
		||||
 | 
			
		||||
public static class Math
 | 
			
		||||
{
 | 
			
		||||
    public const float RadianToDegree = 57.29577866666166f;
 | 
			
		||||
    public const float DegreeToRadian = 0.01745329277777778f;
 | 
			
		||||
 | 
			
		||||
    public static float Clamp(float value, float min, float max) => (value < min) ? min : (value > max) ? max : value;
 | 
			
		||||
}
 | 
			
		||||
@@ -1,68 +0,0 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Physics2D.Primitives;
 | 
			
		||||
 | 
			
		||||
public record Shape(IList<Vector2D> Vertices)
 | 
			
		||||
{
 | 
			
		||||
    public Triangle SuperTriangle
 | 
			
		||||
    {
 | 
			
		||||
        get
 | 
			
		||||
        {
 | 
			
		||||
            float minX = float.MaxValue, minY = float.MaxValue;
 | 
			
		||||
            float maxX = float.MinValue, maxY = float.MinValue;
 | 
			
		||||
 | 
			
		||||
            foreach (Vector2D point in Vertices)
 | 
			
		||||
            {
 | 
			
		||||
                minX = MathF.Min(minX, point.X);
 | 
			
		||||
                minY = MathF.Min(minY, point.Y);
 | 
			
		||||
                maxX = MathF.Max(maxX, point.X);
 | 
			
		||||
                maxY = MathF.Max(maxY, point.Y);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            float dx = maxX - minX;
 | 
			
		||||
            float dy = maxY - minY;
 | 
			
		||||
            float deltaMax = MathF.Max(dx, dy);
 | 
			
		||||
            float midX = (minX + maxX) / 2;
 | 
			
		||||
            float midY = (minY + maxY) / 2;
 | 
			
		||||
 | 
			
		||||
            Vector2D p1 = new Vector2D((float)midX - 20f * (float)deltaMax, (float)midY - (float)deltaMax);
 | 
			
		||||
            Vector2D p2 = new Vector2D((float)midX, (float)midY + 20 * (float)deltaMax);
 | 
			
		||||
            Vector2D p3 = new Vector2D((float)midX + 20 * (float)deltaMax, (float)midY - (float)deltaMax);
 | 
			
		||||
 | 
			
		||||
            return new Triangle(p1, p2, p3);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public List<Line> Lines
 | 
			
		||||
    {
 | 
			
		||||
        get
 | 
			
		||||
        {
 | 
			
		||||
            List<Line> lines = new List<Line>(Vertices.Count - 1);
 | 
			
		||||
            GetLinesNonAlloc(lines);
 | 
			
		||||
            return lines;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void GetLinesNonAlloc(IList<Line> lines)
 | 
			
		||||
    {
 | 
			
		||||
        lines.Clear();
 | 
			
		||||
        for (int i = 0; i < Vertices.Count - 1; i++)
 | 
			
		||||
            lines.Add(new(Vertices[i], Vertices[i + 1]));
 | 
			
		||||
        lines.Add(new(Vertices[^1], Vertices[0]));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public bool ApproximatelyEquals(Shape other)
 | 
			
		||||
    {
 | 
			
		||||
        if (Vertices.Count != other.Vertices.Count)
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        for (int i = 0; i < Vertices.Count; i++)
 | 
			
		||||
            if (!Vertices[i].ApproximatelyEquals(other.Vertices[i]))
 | 
			
		||||
                return false;
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,54 +0,0 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Physics2D.Primitives;
 | 
			
		||||
 | 
			
		||||
public record Triangle(Vector2D A, Vector2D B, Vector2D C)
 | 
			
		||||
{
 | 
			
		||||
    public float Area => MathF.Abs((
 | 
			
		||||
            A.X * (B.Y - C.Y) +
 | 
			
		||||
            B.X * (C.Y - A.Y) +
 | 
			
		||||
            C.X * (A.Y - B.Y)
 | 
			
		||||
            ) * .5f);
 | 
			
		||||
 | 
			
		||||
    public Circle CircumCircle
 | 
			
		||||
    {
 | 
			
		||||
        get
 | 
			
		||||
        {
 | 
			
		||||
            Vector2D midAB = (A + B) / 2;
 | 
			
		||||
            Vector2D midBC = (B + C) / 2;
 | 
			
		||||
 | 
			
		||||
            float slopeAB = (B.Y - A.Y) / (B.X - A.X);
 | 
			
		||||
            float slopeBC = (C.Y - B.Y) / (C.X - B.X);
 | 
			
		||||
 | 
			
		||||
            Vector2D center;
 | 
			
		||||
            if (MathF.Abs(slopeAB - slopeBC) > float.Epsilon)
 | 
			
		||||
            {
 | 
			
		||||
                float x = (slopeAB * slopeBC * (A.Y - C.Y) + slopeBC * (A.X + B.X) - slopeAB * (B.X + C.X)) / (2 * (slopeBC - slopeAB));
 | 
			
		||||
                float y = -(x - (A.X + B.X) / 2) / slopeAB + (A.Y + B.Y) / 2;
 | 
			
		||||
                center = new Vector2D(x, y);
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
                center = (midAB + midBC) * .5f;
 | 
			
		||||
 | 
			
		||||
            return new(center, Vector2D.Distance(center, A));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public bool Overlaps(Vector2D point)
 | 
			
		||||
    {
 | 
			
		||||
        float originalTriangleArea = Area;
 | 
			
		||||
 | 
			
		||||
        float pointTriangleArea1 = new Triangle(point, B, C).Area;
 | 
			
		||||
        float pointTriangleArea2 = new Triangle(A, point, C).Area;
 | 
			
		||||
        float pointTriangleArea3 = new Triangle(A, B, point).Area;
 | 
			
		||||
 | 
			
		||||
        float pointTriangleAreasSum = pointTriangleArea1 + pointTriangleArea2 + pointTriangleArea3;
 | 
			
		||||
 | 
			
		||||
        return originalTriangleArea.ApproximatelyEquals(pointTriangleAreasSum, float.Epsilon * 3f);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public bool ApproximatelyEquals(Triangle other)
 | 
			
		||||
        => A.ApproximatelyEquals(other.A) && B.ApproximatelyEquals(other.B) && C.ApproximatelyEquals(other.C);
 | 
			
		||||
}
 | 
			
		||||
@@ -1,24 +0,0 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
using Syntriax.Engine.Core.Abstract;
 | 
			
		||||
using Syntriax.Engine.Physics2D.Abstract;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Physics2D;
 | 
			
		||||
 | 
			
		||||
public class RigidBody2D : BehaviourOverride, IRigidBody2D
 | 
			
		||||
{
 | 
			
		||||
    public Action<IAssignableTransform>? OnTransformAssigned { get => GameObject.OnTransformAssigned; set => GameObject.OnTransformAssigned = value; }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    public IPhysicsMaterial2D Material { get; set; } = new PhysicsMaterial2DDefault();
 | 
			
		||||
 | 
			
		||||
    public Vector2D Velocity { get; set; } = Vector2D.Zero;
 | 
			
		||||
    public float AngularVelocity { get; set; } = 0f;
 | 
			
		||||
    public float Mass { get; set; } = 0f;
 | 
			
		||||
 | 
			
		||||
    ITransform IAssignableTransform.Transform => Transform;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    public bool Assign(ITransform transform) => GameObject.Assign(transform);
 | 
			
		||||
}
 | 
			
		||||
@@ -1,3 +0,0 @@
 | 
			
		||||
 | 
			
		||||
using var game = new Pong.Game1();
 | 
			
		||||
game.Run();
 | 
			
		||||
@@ -3,31 +3,31 @@
 | 
			
		||||
  "isRoot": true,
 | 
			
		||||
  "tools": {
 | 
			
		||||
    "dotnet-mgcb": {
 | 
			
		||||
      "version": "3.8.1.303",
 | 
			
		||||
      "version": "3.8.2.1105",
 | 
			
		||||
      "commands": [
 | 
			
		||||
        "mgcb"
 | 
			
		||||
      ]
 | 
			
		||||
    },
 | 
			
		||||
    "dotnet-mgcb-editor": {
 | 
			
		||||
      "version": "3.8.1.303",
 | 
			
		||||
      "version": "3.8.2.1105",
 | 
			
		||||
      "commands": [
 | 
			
		||||
        "mgcb-editor"
 | 
			
		||||
      ]
 | 
			
		||||
    },
 | 
			
		||||
    "dotnet-mgcb-editor-linux": {
 | 
			
		||||
      "version": "3.8.1.303",
 | 
			
		||||
      "version": "3.8.2.1105",
 | 
			
		||||
      "commands": [
 | 
			
		||||
        "mgcb-editor-linux"
 | 
			
		||||
      ]
 | 
			
		||||
    },
 | 
			
		||||
    "dotnet-mgcb-editor-windows": {
 | 
			
		||||
      "version": "3.8.1.303",
 | 
			
		||||
      "version": "3.8.2.1105",
 | 
			
		||||
      "commands": [
 | 
			
		||||
        "mgcb-editor-windows"
 | 
			
		||||
      ]
 | 
			
		||||
    },
 | 
			
		||||
    "dotnet-mgcb-editor-mac": {
 | 
			
		||||
      "version": "3.8.1.303",
 | 
			
		||||
      "version": "3.8.2.1105",
 | 
			
		||||
      "commands": [
 | 
			
		||||
        "mgcb-editor-mac"
 | 
			
		||||
      ]
 | 
			
		||||
							
								
								
									
										11
									
								
								Platforms/Desktop/ClientConfiguration.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,11 @@
 | 
			
		||||
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;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										15
									
								
								Platforms/Desktop/Content/Content.mgcb
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,15 @@
 | 
			
		||||
 | 
			
		||||
#----------------------------- Global Properties ----------------------------#
 | 
			
		||||
 | 
			
		||||
/outputDir:bin/$(Platform)
 | 
			
		||||
/intermediateDir:obj/$(Platform)
 | 
			
		||||
/platform:DesktopGL
 | 
			
		||||
/config:
 | 
			
		||||
/profile:Reach
 | 
			
		||||
/compress:False
 | 
			
		||||
 | 
			
		||||
#-------------------------------- References --------------------------------#
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#---------------------------------- Content ---------------------------------#
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										90
									
								
								Platforms/Desktop/Desktop.csproj
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,90 @@
 | 
			
		||||
<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.Serializers\Engine.Serializers.Yaml\Engine.Serializers.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>
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								Platforms/Desktop/Icon.bmp
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 192 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								Platforms/Desktop/Icon.ico
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 7.2 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								Platforms/Desktop/Icon.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 7.2 KiB  | 
							
								
								
									
										59
									
								
								Platforms/Desktop/Program.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,59 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.IO;
 | 
			
		||||
 | 
			
		||||
using Microsoft.Xna.Framework.Graphics;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
using Syntriax.Engine.Core.Debug;
 | 
			
		||||
using Syntriax.Engine.Core.Serialization;
 | 
			
		||||
using Syntriax.Engine.Integration.MonoGame;
 | 
			
		||||
using Syntriax.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 = logger;
 | 
			
		||||
 | 
			
		||||
string settingsPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "settings.yaml");
 | 
			
		||||
ClientConfiguration clientConfiguration;
 | 
			
		||||
try
 | 
			
		||||
{
 | 
			
		||||
    clientConfiguration = serializer.Deserialize<ClientConfiguration>(File.ReadAllText(settingsPath));
 | 
			
		||||
    logger.Log(clientConfiguration, $"{settingsPath} read");
 | 
			
		||||
}
 | 
			
		||||
catch (Exception exception)
 | 
			
		||||
{
 | 
			
		||||
    clientConfiguration = new();
 | 
			
		||||
    logger.LogError(serializer, $"Error loading {settingsPath}. Creating new settings file");
 | 
			
		||||
    logger.LogException(serializer, exception);
 | 
			
		||||
    File.WriteAllText(settingsPath, serializer.Serialize(clientConfiguration));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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<Syntriax.Engine.Network.INetworkCommunicatorClient>()?
 | 
			
		||||
    .OnConnectionEstablished.AddOneTimeListener(
 | 
			
		||||
        (sender, connection) => monoGameWindow.Window.Title = $"Client {connection.Id}"
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
monoGameWindow.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="Game"/>
 | 
			
		||||
  <assemblyIdentity version="1.0.0.0" name="Desktop"/>
 | 
			
		||||
  <trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
 | 
			
		||||
    <security>
 | 
			
		||||
      <requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
 | 
			
		||||
							
								
								
									
										131
									
								
								Platforms/Desktop/icon.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,131 @@
 | 
			
		||||
<?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>
 | 
			
		||||
| 
		 After Width: | Height: | Size: 4.2 KiB  | 
							
								
								
									
										39
									
								
								Platforms/Server/PongEndpoints.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,39 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
using Microsoft.AspNetCore.Builder;
 | 
			
		||||
using Microsoft.AspNetCore.Http;
 | 
			
		||||
using Microsoft.Extensions.DependencyInjection;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
using Syntriax.Engine.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;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										34
									
								
								Platforms/Server/Program.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,34 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Threading;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
using Syntriax.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 = 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);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										20
									
								
								Platforms/Server/Server.csproj
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,20 @@
 | 
			
		||||
<Project Sdk="Microsoft.NET.Sdk.Web">
 | 
			
		||||
 | 
			
		||||
  <PropertyGroup>
 | 
			
		||||
    <OutputType>Exe</OutputType>
 | 
			
		||||
    <TargetFramework>net9.0</TargetFramework>
 | 
			
		||||
    <ImplicitUsings>disable</ImplicitUsings>
 | 
			
		||||
    <Nullable>enable</Nullable>
 | 
			
		||||
  </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>
 | 
			
		||||
							
								
								
									
										159
									
								
								Pong.sln
									
									
									
									
									
								
							
							
						
						@@ -7,41 +7,160 @@ 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}"
 | 
			
		||||
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.Input", "Engine\Engine.Input\Engine.Input.csproj", "{7EED4EC3-79D5-4C6C-A54D-1B396213C0E4}"
 | 
			
		||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Engine", "Engine\Engine\Engine.csproj", "{2F6B1E26-1217-4EFD-874C-05ADEE4C7969}"
 | 
			
		||||
EndProject
 | 
			
		||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Engine.Graphics", "Engine\Engine.Graphics\Engine.Graphics.csproj", "{7371D9AF-6F4D-4F05-8458-197C4EE66B01}"
 | 
			
		||||
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("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Engine.Serializers", "Engine.Serializers", "{F1257AE1-A8BC-DE44-CB86-406F1335A1D0}"
 | 
			
		||||
EndProject
 | 
			
		||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Engine.Serializers.Yaml", "Engine\Engine.Serializers\Engine.Serializers.Yaml\Engine.Serializers.Yaml.csproj", "{79F870AB-249E-4CA0-9DF0-F265514581DF}"
 | 
			
		||||
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
 | 
			
		||||
	EndGlobalSection
 | 
			
		||||
	GlobalSection(SolutionProperties) = preSolution
 | 
			
		||||
		HideSolutionNode = FALSE
 | 
			
		||||
		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
 | 
			
		||||
		{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
 | 
			
		||||
		{7371D9AF-6F4D-4F05-8458-197C4EE66B01}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 | 
			
		||||
		{7371D9AF-6F4D-4F05-8458-197C4EE66B01}.Debug|Any CPU.Build.0 = Debug|Any CPU
 | 
			
		||||
		{7371D9AF-6F4D-4F05-8458-197C4EE66B01}.Release|Any CPU.ActiveCfg = Release|Any CPU
 | 
			
		||||
		{7371D9AF-6F4D-4F05-8458-197C4EE66B01}.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
 | 
			
		||||
	EndGlobalSection
 | 
			
		||||
	GlobalSection(SolutionProperties) = preSolution
 | 
			
		||||
		HideSolutionNode = FALSE
 | 
			
		||||
	EndGlobalSection
 | 
			
		||||
	GlobalSection(NestedProjects) = preSolution
 | 
			
		||||
		{990CA10C-1EBB-4395-A43A-456B7029D8C9} = {F7F62670-237A-4C93-A30E-CE661C6FC401}
 | 
			
		||||
		{7EED4EC3-79D5-4C6C-A54D-1B396213C0E4} = {F7F62670-237A-4C93-A30E-CE661C6FC401}
 | 
			
		||||
		{7371D9AF-6F4D-4F05-8458-197C4EE66B01} = {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}
 | 
			
		||||
		{F1257AE1-A8BC-DE44-CB86-406F1335A1D0} = {F7F62670-237A-4C93-A30E-CE661C6FC401}
 | 
			
		||||
		{79F870AB-249E-4CA0-9DF0-F265514581DF} = {F1257AE1-A8BC-DE44-CB86-406F1335A1D0}
 | 
			
		||||
	EndGlobalSection
 | 
			
		||||
EndGlobal
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										36
									
								
								Shared/.config/dotnet-tools.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,36 @@
 | 
			
		||||
{
 | 
			
		||||
  "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"
 | 
			
		||||
      ]
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										94
									
								
								Shared/Behaviours/Ball.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,94 @@
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
using Syntriax.Engine.Network;
 | 
			
		||||
using Syntriax.Engine.Physics2D;
 | 
			
		||||
using Syntriax.Engine.Systems.Tween;
 | 
			
		||||
 | 
			
		||||
namespace Pong.Behaviours;
 | 
			
		||||
 | 
			
		||||
public class Ball : Behaviour2D, IFirstFrameUpdate, 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;
 | 
			
		||||
 | 
			
		||||
    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 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);
 | 
			
		||||
        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;
 | 
			
		||||
 | 
			
		||||
        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;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										69
									
								
								Shared/Behaviours/CameraController.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,69 @@
 | 
			
		||||
using Microsoft.Xna.Framework.Input;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
using Syntriax.Engine.Integration.MonoGame;
 | 
			
		||||
using Syntriax.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;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										29
									
								
								Shared/Behaviours/DrawableColliderCircle.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,29 @@
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
using Syntriax.Engine.Integration.MonoGame;
 | 
			
		||||
 | 
			
		||||
namespace Pong.Behaviours;
 | 
			
		||||
 | 
			
		||||
public class DrawableColliderCircle : Syntriax.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; }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										26
									
								
								Shared/Behaviours/DrawableColliderShape.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,26 @@
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
using Syntriax.Engine.Integration.MonoGame;
 | 
			
		||||
 | 
			
		||||
namespace Pong.Behaviours;
 | 
			
		||||
 | 
			
		||||
public class DrawableColliderShape : Syntriax.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; }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										25
									
								
								Shared/Behaviours/Label.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,25 @@
 | 
			
		||||
using Microsoft.Xna.Framework;
 | 
			
		||||
using Microsoft.Xna.Framework.Graphics;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
using Syntriax.Engine.Integration.MonoGame;
 | 
			
		||||
 | 
			
		||||
namespace Pong.Behaviours;
 | 
			
		||||
 | 
			
		||||
public class Label : Behaviour2D, IDrawableSprite
 | 
			
		||||
{
 | 
			
		||||
    public SpriteFont? Font { get; set; } = null;
 | 
			
		||||
    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.White, Transform.Rotation, Vector2D.One * .5f, Transform.Scale.Magnitude, SpriteEffects.None, 0f);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Label() { }
 | 
			
		||||
    public Label(SpriteFont font) => Font = font;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										126
									
								
								Shared/Behaviours/Paddle.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,126 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
using Microsoft.Xna.Framework.Input;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
using Syntriax.Engine.Network;
 | 
			
		||||
using Syntriax.Engine.Physics2D;
 | 
			
		||||
using Syntriax.Engine.Systems.Input;
 | 
			
		||||
using Syntriax.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);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected override void OnFinalize()
 | 
			
		||||
    {
 | 
			
		||||
        inputs?.UnregisterOnPress(Up, OnUpPressed);
 | 
			
		||||
        inputs?.UnregisterOnRelease(Up, OnUpReleased);
 | 
			
		||||
 | 
			
		||||
        inputs?.UnregisterOnPress(Down, OnDownPressed);
 | 
			
		||||
        inputs?.UnregisterOnRelease(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);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										134
									
								
								Shared/Behaviours/PongManager.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,134 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
using Microsoft.Xna.Framework.Input;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
using Syntriax.Engine.Core.Debug;
 | 
			
		||||
using Syntriax.Engine.Network;
 | 
			
		||||
using Syntriax.Engine.Systems.Input;
 | 
			
		||||
 | 
			
		||||
namespace Pong.Behaviours;
 | 
			
		||||
 | 
			
		||||
public class PongManager : Behaviour, INetworkEntity, IFirstFrameUpdate,
 | 
			
		||||
    IPacketListenerServer<PongManager.RequestStartPacket>,
 | 
			
		||||
    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 Ball ball = null!;
 | 
			
		||||
 | 
			
		||||
    private INetworkCommunicatorClient? networkClient = null!;
 | 
			
		||||
    private INetworkCommunicatorServer? networkServer = null;
 | 
			
		||||
    private ILogger? logger = 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 PongManager() => WinScore = 5;
 | 
			
		||||
    public PongManager(int winScore) => WinScore = winScore;
 | 
			
		||||
 | 
			
		||||
    public void FirstActiveFrame()
 | 
			
		||||
    {
 | 
			
		||||
        IButtonInputs<Keys>? buttonInputs = Universe.FindBehaviour<IButtonInputs<Keys>>();
 | 
			
		||||
        buttonInputs?.RegisterOnRelease(Keys.Space, (_, _1) => networkClient?.SendToServer(new RequestStartPacket()));
 | 
			
		||||
 | 
			
		||||
        ball = Universe.FindRequiredBehaviour<Ball>();
 | 
			
		||||
        networkClient = Universe.FindBehaviour<INetworkCommunicatorClient>();
 | 
			
		||||
        networkServer = Universe.FindBehaviour<INetworkCommunicatorServer>();
 | 
			
		||||
        logger = Universe.FindBehaviour<ILogger>();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void ScoreToLeft()
 | 
			
		||||
    {
 | 
			
		||||
        ScoreLeft++;
 | 
			
		||||
        OnScoreUpdated?.Invoke(this);
 | 
			
		||||
 | 
			
		||||
        PostScoreUpdate();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void ScoreToRight()
 | 
			
		||||
    {
 | 
			
		||||
        ScoreRight++;
 | 
			
		||||
        OnScoreUpdated?.Invoke(this);
 | 
			
		||||
 | 
			
		||||
        PostScoreUpdate();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void Reset()
 | 
			
		||||
    {
 | 
			
		||||
        ScoreLeft = ScoreRight = 0;
 | 
			
		||||
 | 
			
		||||
        PostScoreUpdate();
 | 
			
		||||
 | 
			
		||||
        OnReset?.Invoke(this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void PostScoreUpdate()
 | 
			
		||||
    {
 | 
			
		||||
        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)
 | 
			
		||||
        {
 | 
			
		||||
            OnFinished?.Invoke(this);
 | 
			
		||||
            logger?.Log(this, $"Game finished");
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        ball.LaunchBall(GetBallLaunchDirection());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private Vector2D GetBallLaunchDirection()
 | 
			
		||||
    {
 | 
			
		||||
        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);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void IPacketListenerClient<ScorePacket>.OnClientPacketArrived(IConnection sender, ScorePacket packet)
 | 
			
		||||
    {
 | 
			
		||||
        ScoreLeft = packet.Left;
 | 
			
		||||
        ScoreRight = packet.Right;
 | 
			
		||||
 | 
			
		||||
        OnScoreUpdated?.Invoke(this);
 | 
			
		||||
        logger?.Log(this, $"Client score update packet arrived: {packet.Left} - {packet.Right}");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void IPacketListenerServer<RequestStartPacket>.OnServerPacketArrived(IConnection sender, RequestStartPacket packet)
 | 
			
		||||
    {
 | 
			
		||||
        logger?.Log(this, $"{sender} requested start");
 | 
			
		||||
        if (ball.RigidBody.Velocity.MagnitudeSquared > 0.01f)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        Reset();
 | 
			
		||||
        ball.LaunchBall(GetBallLaunchDirection());
 | 
			
		||||
        logger?.Log(this, $"Game started");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private class RequestStartPacket : 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;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										34
									
								
								Shared/Behaviours/ScoreLabel.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,34 @@
 | 
			
		||||
using Microsoft.Xna.Framework.Graphics;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
using Syntriax.Engine.Integration.MonoGame;
 | 
			
		||||
 | 
			
		||||
namespace Pong.Behaviours;
 | 
			
		||||
 | 
			
		||||
public class ScoreLabel(bool IsLeft) : Label, IFirstFrameUpdate
 | 
			
		||||
{
 | 
			
		||||
    public readonly bool IsLeft = IsLeft;
 | 
			
		||||
 | 
			
		||||
    private PongManager pongManager = null!;
 | 
			
		||||
 | 
			
		||||
    public void FirstActiveFrame()
 | 
			
		||||
    {
 | 
			
		||||
        MonoGameWindow monoGameWindow = Universe.FindRequiredBehaviour<MonoGameWindowContainer>().Window;
 | 
			
		||||
        Font = monoGameWindow.Content.Load<SpriteFont>("UbuntuMono");
 | 
			
		||||
 | 
			
		||||
        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();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										19
									
								
								Shared/Behaviours/ScoreWall.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,19 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
using Syntriax.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());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										22
									
								
								Shared/Content/Content.mgcb
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,22 @@
 | 
			
		||||
 | 
			
		||||
#----------------------------- Global Properties ----------------------------#
 | 
			
		||||
 | 
			
		||||
/outputDir:bin/$(Platform)
 | 
			
		||||
/intermediateDir:obj/$(Platform)
 | 
			
		||||
/platform:DesktopGL
 | 
			
		||||
/config:
 | 
			
		||||
/profile:Reach
 | 
			
		||||
/compress:False
 | 
			
		||||
 | 
			
		||||
#-------------------------------- References --------------------------------#
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#---------------------------------- Content ---------------------------------#
 | 
			
		||||
 | 
			
		||||
#begin UbuntuMono.spritefont
 | 
			
		||||
/importer:FontDescriptionImporter
 | 
			
		||||
/processor:FontDescriptionProcessor
 | 
			
		||||
/processorParam:PremultiplyAlpha=True
 | 
			
		||||
/processorParam:TextureFormat=Compressed
 | 
			
		||||
/build:UbuntuMono.spritefont
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								Shared/Content/Ubuntu Mono.ttf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										60
									
								
								Shared/Content/UbuntuMono.spritefont
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,60 @@
 | 
			
		||||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<!--
 | 
			
		||||
This file contains an xml description of a font, and will be read by the XNA
 | 
			
		||||
Framework Content Pipeline. Follow the comments to customize the appearance
 | 
			
		||||
of the font in your game, and to change the characters which are available to draw
 | 
			
		||||
with.
 | 
			
		||||
-->
 | 
			
		||||
<XnaContent xmlns:Graphics="Microsoft.Xna.Framework.Content.Pipeline.Graphics">
 | 
			
		||||
  <Asset Type="Graphics:FontDescription">
 | 
			
		||||
 | 
			
		||||
    <!--
 | 
			
		||||
    Modify this string to change the font that will be imported.
 | 
			
		||||
    -->
 | 
			
		||||
    <FontName>Ubuntu Mono</FontName>
 | 
			
		||||
 | 
			
		||||
    <!--
 | 
			
		||||
    Size is a float value, measured in points. Modify this value to change
 | 
			
		||||
    the size of the font.
 | 
			
		||||
    -->
 | 
			
		||||
    <Size>144</Size>
 | 
			
		||||
 | 
			
		||||
    <!--
 | 
			
		||||
    Spacing is a float value, measured in pixels. Modify this value to change
 | 
			
		||||
    the amount of spacing in between characters.
 | 
			
		||||
    -->
 | 
			
		||||
    <Spacing>0</Spacing>
 | 
			
		||||
 | 
			
		||||
    <!--
 | 
			
		||||
    UseKerning controls the layout of the font. If this value is true, kerning information
 | 
			
		||||
    will be used when placing characters.
 | 
			
		||||
    -->
 | 
			
		||||
    <UseKerning>true</UseKerning>
 | 
			
		||||
 | 
			
		||||
    <!--
 | 
			
		||||
    Style controls the style of the font. Valid entries are "Regular", "Bold", "Italic",
 | 
			
		||||
    and "Bold, Italic", and are case sensitive.
 | 
			
		||||
    -->
 | 
			
		||||
    <Style>Bold</Style>
 | 
			
		||||
 | 
			
		||||
    <!--
 | 
			
		||||
    If you uncomment this line, the default character will be substituted if you draw
 | 
			
		||||
    or measure text that contains characters which were not included in the font.
 | 
			
		||||
    -->
 | 
			
		||||
    <!-- <DefaultCharacter>*</DefaultCharacter> -->
 | 
			
		||||
 | 
			
		||||
    <!--
 | 
			
		||||
    CharacterRegions control what letters are available in the font. Every
 | 
			
		||||
    character from Start to End will be built and made available for drawing. The
 | 
			
		||||
    default range is from 32, (ASCII space), to 126, ('~'), covering the basic Latin
 | 
			
		||||
    character set. The characters are ordered according to the Unicode standard.
 | 
			
		||||
    See the documentation for more information.
 | 
			
		||||
    -->
 | 
			
		||||
    <CharacterRegions>
 | 
			
		||||
      <CharacterRegion>
 | 
			
		||||
        <Start> </Start>
 | 
			
		||||
        <End>~</End>
 | 
			
		||||
      </CharacterRegion>
 | 
			
		||||
    </CharacterRegions>
 | 
			
		||||
  </Asset>
 | 
			
		||||
</XnaContent>
 | 
			
		||||
							
								
								
									
										12
									
								
								Shared/Network/Abstract/IConnection.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,12 @@
 | 
			
		||||
namespace Syntriax.Engine.Network;
 | 
			
		||||
 | 
			
		||||
public interface IConnection
 | 
			
		||||
{
 | 
			
		||||
    string Id { get; }
 | 
			
		||||
 | 
			
		||||
    float Ping { get; }
 | 
			
		||||
    float RoundTrip { get; }
 | 
			
		||||
 | 
			
		||||
    int PingMs { get; }
 | 
			
		||||
    int RoundTripMs { get; }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										6
									
								
								Shared/Network/Abstract/IEntityNetworkPacket.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,6 @@
 | 
			
		||||
namespace Syntriax.Engine.Network;
 | 
			
		||||
 | 
			
		||||
public interface IEntityNetworkPacket : INetworkPacket
 | 
			
		||||
{
 | 
			
		||||
    string EntityId { get; }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										37
									
								
								Shared/Network/Abstract/INetworkCommunicator.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,37 @@
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Network;
 | 
			
		||||
 | 
			
		||||
public interface INetworkCommunicator
 | 
			
		||||
{
 | 
			
		||||
    Event<INetworkCommunicator, IConnection> OnConnectionEstablished { get; }
 | 
			
		||||
    Event<INetworkCommunicator, IConnection> OnConnectionAbolished { get; }
 | 
			
		||||
 | 
			
		||||
    IReadOnlyDictionary<string, IConnection> Connections { get; }
 | 
			
		||||
 | 
			
		||||
    INetworkCommunicator Stop();
 | 
			
		||||
 | 
			
		||||
    INetworkCommunicator SubscribeToPackets<T>(Event<IConnection, T>.EventHandler callback);
 | 
			
		||||
    INetworkCommunicator UnsubscribeFromPackets<T>(Event<IConnection, T>.EventHandler callback);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
public interface INetworkCommunicatorClient : INetworkCommunicator
 | 
			
		||||
{
 | 
			
		||||
    INetworkCommunicatorClient Connect(string address, int port, string? password = null);
 | 
			
		||||
 | 
			
		||||
    INetworkCommunicatorClient SendToServer<T>(T packet, PacketDelivery packetDelivery = PacketDelivery.ReliableInOrder) where T : class, new();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
public interface INetworkCommunicatorServer : INetworkCommunicator
 | 
			
		||||
{
 | 
			
		||||
    string Password { get; }
 | 
			
		||||
    int MaxConnectionCount { get; }
 | 
			
		||||
    int Port { get; }
 | 
			
		||||
 | 
			
		||||
    INetworkCommunicatorServer Start(int port, int maxConnectionCount, string? password = null);
 | 
			
		||||
 | 
			
		||||
    INetworkCommunicatorServer SendToClient<T>(IConnection connection, T packet, PacketDelivery packetDelivery = PacketDelivery.ReliableInOrder) where T : class, new();
 | 
			
		||||
    INetworkCommunicatorServer SendToAll<T>(T packet, PacketDelivery packetDelivery = PacketDelivery.ReliableInOrder) where T : class, new();
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										5
									
								
								Shared/Network/Abstract/INetworkEntity.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,5 @@
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Network;
 | 
			
		||||
 | 
			
		||||
public interface INetworkEntity : IEntity;
 | 
			
		||||
							
								
								
									
										11
									
								
								Shared/Network/Abstract/INetworkManager.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,11 @@
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Network;
 | 
			
		||||
 | 
			
		||||
public interface INetworkManager
 | 
			
		||||
{
 | 
			
		||||
    IReadOnlyDictionary<string, INetworkEntity> NetworkEntities { get; }
 | 
			
		||||
    IBehaviourCollector<INetworkEntity> NetworkEntityCollector { get; }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										3
									
								
								Shared/Network/Abstract/INetworkPacket.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,3 @@
 | 
			
		||||
namespace Syntriax.Engine.Network;
 | 
			
		||||
 | 
			
		||||
public interface INetworkPacket;
 | 
			
		||||
							
								
								
									
										6
									
								
								Shared/Network/Abstract/IPacketListenerClient.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,6 @@
 | 
			
		||||
namespace Syntriax.Engine.Network;
 | 
			
		||||
 | 
			
		||||
public interface IPacketListenerClient<T> : INetworkEntity
 | 
			
		||||
{
 | 
			
		||||
    void OnClientPacketArrived(IConnection sender, T packet);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										6
									
								
								Shared/Network/Abstract/IPacketListenerServer.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,6 @@
 | 
			
		||||
namespace Syntriax.Engine.Network;
 | 
			
		||||
 | 
			
		||||
public interface IPacketListenerServer<T> : INetworkEntity
 | 
			
		||||
{
 | 
			
		||||
    void OnServerPacketArrived(IConnection sender, T packet);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										9
									
								
								Shared/Network/Abstract/PacketDelivery.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,9 @@
 | 
			
		||||
namespace Syntriax.Engine.Network;
 | 
			
		||||
 | 
			
		||||
public enum PacketDelivery
 | 
			
		||||
{
 | 
			
		||||
    ReliableInOrder,
 | 
			
		||||
    ReliableOutOfOrder,
 | 
			
		||||
    UnreliableInOrder,
 | 
			
		||||
    UnreliableOutOfOrder,
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										89
									
								
								Shared/Network/LiteNetLib/LiteNetLibClient.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,89 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Net.Sockets;
 | 
			
		||||
using System.Threading;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
using LiteNetLib;
 | 
			
		||||
using LiteNetLib.Utils;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
using Syntriax.Engine.Core.Debug;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Network;
 | 
			
		||||
 | 
			
		||||
public class LiteNetLibClient : LiteNetLibCommunicatorBase, INetworkCommunicatorClient
 | 
			
		||||
{
 | 
			
		||||
    private readonly NetDataWriter netDataWriter = new();
 | 
			
		||||
 | 
			
		||||
    private CancellationTokenSource? cancellationTokenSource = null;
 | 
			
		||||
 | 
			
		||||
    protected override IConnection GetConnection(NetPeer peer) => new LiteNetLibServerConnection(peer);
 | 
			
		||||
 | 
			
		||||
    public INetworkCommunicatorClient Connect(string address, int port, string? password = null)
 | 
			
		||||
    {
 | 
			
		||||
        if (!UniverseObject.IsInUniverse)
 | 
			
		||||
            throw new($"{nameof(LiteNetLibClient)} must be in an universe to connect");
 | 
			
		||||
 | 
			
		||||
        password ??= string.Empty;
 | 
			
		||||
 | 
			
		||||
        // Okay, for some reason sometimes LiteNetLib goes dumb when the server hostname has IPv6 address as well as IPv4
 | 
			
		||||
        // but the client doesn't support IPv6, it still tries to use the v6 unless we explicitly tell the ip to connect to,
 | 
			
		||||
        // which fails to connect... So for the time being I am preferring IPv4 below over IPv6 for clients.
 | 
			
		||||
        // TODO: I think this is something that happens on Linux only? I need to check on Windows as well just to be sure.
 | 
			
		||||
        System.Net.IPAddress[] addresses = System.Net.Dns.GetHostAddresses(address);
 | 
			
		||||
        string connectionAddress = addresses.FirstOrDefault(a => a.AddressFamily == AddressFamily.InterNetwork, addresses[0]).ToString();
 | 
			
		||||
 | 
			
		||||
        logger?.Log(this, $"Connecting to server at '{address}:{port}' with password '{password}'");
 | 
			
		||||
        logger?.Log(this, $"Resolved address for {address}: {connectionAddress}");
 | 
			
		||||
 | 
			
		||||
        Manager.Start();
 | 
			
		||||
        Manager.Connect(connectionAddress, port, password);
 | 
			
		||||
 | 
			
		||||
        return this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public INetworkCommunicatorClient SendToServer<T>(T packet, PacketDelivery packetDelivery) where T : class, new()
 | 
			
		||||
    {
 | 
			
		||||
        netDataWriter.Reset();
 | 
			
		||||
        netPacketProcessor.Write(netDataWriter, packet);
 | 
			
		||||
 | 
			
		||||
        switch (packetDelivery)
 | 
			
		||||
        {
 | 
			
		||||
            case PacketDelivery.ReliableInOrder: Manager.FirstPeer.Send(netDataWriter, DeliveryMethod.ReliableOrdered); break;
 | 
			
		||||
            case PacketDelivery.UnreliableInOrder: Manager.FirstPeer.Send(netDataWriter, DeliveryMethod.Sequenced); break;
 | 
			
		||||
            case PacketDelivery.ReliableOutOfOrder: Manager.FirstPeer.Send(netDataWriter, DeliveryMethod.ReliableUnordered); break;
 | 
			
		||||
            case PacketDelivery.UnreliableOutOfOrder: Manager.FirstPeer.Send(netDataWriter, DeliveryMethod.Unreliable); break;
 | 
			
		||||
            default: Manager.FirstPeer.Send(netDataWriter, DeliveryMethod.ReliableOrdered); break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected override void OnEnteredUniverse(IUniverse universe)
 | 
			
		||||
    {
 | 
			
		||||
        base.OnEnteredUniverse(universe);
 | 
			
		||||
 | 
			
		||||
        cancellationTokenSource = new CancellationTokenSource();
 | 
			
		||||
        PollEvents(cancellationTokenSource.Token);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected override void OnExitedUniverse(IUniverse universe)
 | 
			
		||||
    {
 | 
			
		||||
        base.OnExitedUniverse(universe);
 | 
			
		||||
        cancellationTokenSource?.Cancel();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// <summary>
 | 
			
		||||
    /// Client needs to send everything as soon as possible so 
 | 
			
		||||
    /// the events are polled a separate thread running constantly 
 | 
			
		||||
    /// </summary>
 | 
			
		||||
    private async void PollEvents(CancellationToken cancellationToken) => await Task.Run(() =>
 | 
			
		||||
    {
 | 
			
		||||
        while (true)
 | 
			
		||||
        {
 | 
			
		||||
            Manager.PollEvents();
 | 
			
		||||
            Thread.Sleep(1);
 | 
			
		||||
        }
 | 
			
		||||
    }, cancellationToken);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										16
									
								
								Shared/Network/LiteNetLib/LiteNetLibClientConnection.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,16 @@
 | 
			
		||||
using LiteNetLib;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Network;
 | 
			
		||||
 | 
			
		||||
public record class LiteNetLibClientConnection(NetPeer NetPeer) : IConnection
 | 
			
		||||
{
 | 
			
		||||
    public string Id { get; } = NetPeer.Id.ToString();
 | 
			
		||||
 | 
			
		||||
    public float Ping => NetPeer.Ping * .001f;
 | 
			
		||||
    public float RoundTrip => NetPeer.RoundTripTime * .001f;
 | 
			
		||||
 | 
			
		||||
    public int PingMs => NetPeer.Ping;
 | 
			
		||||
    public int RoundTripMs => NetPeer.RoundTripTime;
 | 
			
		||||
 | 
			
		||||
    public override string ToString() => $"Connection({Id})";
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										189
									
								
								Shared/Network/LiteNetLib/LiteNetLibCommunicatorBase.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,189 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Reflection;
 | 
			
		||||
 | 
			
		||||
using LiteNetLib;
 | 
			
		||||
using LiteNetLib.Utils;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
using Syntriax.Engine.Core.Debug;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Network;
 | 
			
		||||
 | 
			
		||||
public abstract class LiteNetLibCommunicatorBase : Behaviour, INetworkCommunicator
 | 
			
		||||
{
 | 
			
		||||
    protected readonly NetPacketProcessor netPacketProcessor = new();
 | 
			
		||||
 | 
			
		||||
    private readonly Dictionary<Type, Event<IConnection, object>> listeners = [];
 | 
			
		||||
    private readonly Dictionary<string, IConnection> _connections = [];
 | 
			
		||||
 | 
			
		||||
    private readonly Dictionary<int, IConnection> localPeerIdToConnectionDictionary = [];
 | 
			
		||||
 | 
			
		||||
    protected ILogger? logger = null;
 | 
			
		||||
 | 
			
		||||
    public IReadOnlyDictionary<string, IConnection> Connections => _connections;
 | 
			
		||||
    public EventBasedNetListener Listener { get; private set; } = null!;
 | 
			
		||||
    public NetManager Manager { get; private set; } = null!;
 | 
			
		||||
 | 
			
		||||
    public Event<INetworkCommunicator, IConnection> OnConnectionEstablished { get; } = new();
 | 
			
		||||
    public Event<INetworkCommunicator, IConnection> OnConnectionAbolished { get; } = new();
 | 
			
		||||
 | 
			
		||||
    public INetworkCommunicator Stop()
 | 
			
		||||
    {
 | 
			
		||||
        Manager.Stop();
 | 
			
		||||
        return this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected override void OnEnteredUniverse(IUniverse universe)
 | 
			
		||||
    {
 | 
			
		||||
        base.OnEnteredUniverse(universe);
 | 
			
		||||
        logger = universe.FindBehaviour<ILogger>();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected override void OnExitedUniverse(IUniverse universe)
 | 
			
		||||
    {
 | 
			
		||||
        base.OnExitedUniverse(universe);
 | 
			
		||||
        logger = null;
 | 
			
		||||
        Stop();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected virtual void OnPacketArrived<T>(T packet, NetPeer peer) where T : INetworkPacket
 | 
			
		||||
    {
 | 
			
		||||
        if (!listeners.TryGetValue(typeof(T), out Event<IConnection, object>? @event))
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        @event.Invoke(localPeerIdToConnectionDictionary[peer.Id], packet);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void NetworkReceiveEvent(NetPeer peer, NetPacketReader reader, byte channel, DeliveryMethod deliveryMethod)
 | 
			
		||||
    {
 | 
			
		||||
        try { netPacketProcessor.ReadAllPackets(reader, peer); }
 | 
			
		||||
        catch (Exception exception) { logger?.LogException(this, exception, force: true); }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected abstract IConnection GetConnection(NetPeer peer);
 | 
			
		||||
    private void ConnectionEstablished(NetPeer peer)
 | 
			
		||||
    {
 | 
			
		||||
        IConnection connection = GetConnection(peer);
 | 
			
		||||
 | 
			
		||||
        localPeerIdToConnectionDictionary.Add(peer.Id, connection);
 | 
			
		||||
        _connections.Add(connection.Id, connection);
 | 
			
		||||
 | 
			
		||||
        logger?.Log(this, $"Connection established with ip '{peer.Address}' and id '{connection.Id}'");
 | 
			
		||||
        OnConnectionEstablished.Invoke(this, connection);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    private void ConnectionAbolished(NetPeer peer, DisconnectInfo disconnectInfo)
 | 
			
		||||
    {
 | 
			
		||||
        if (!localPeerIdToConnectionDictionary.TryGetValue(peer.Id, out var connection))
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        localPeerIdToConnectionDictionary.Remove(peer.Id);
 | 
			
		||||
        _connections.Remove(connection.Id);
 | 
			
		||||
 | 
			
		||||
        logger?.Log(this, $"Connection abolished with ip '{peer.Address}' and id '{connection.Id}'");
 | 
			
		||||
        OnConnectionAbolished.Invoke(this, connection);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void SetupPackets()
 | 
			
		||||
    {
 | 
			
		||||
        // Find network packets implementing INetworkPacket
 | 
			
		||||
        IEnumerable<Type> packetTypes = AppDomain.CurrentDomain.GetAssemblies().SelectMany(a => a.GetTypes())
 | 
			
		||||
            .Where(t => typeof(INetworkPacket).IsAssignableFrom(t) && !t.IsInterface && !t.IsAbstract && !t.IsGenericType);
 | 
			
		||||
 | 
			
		||||
        MethodInfo subscribeReusableMethod = typeof(NetPacketProcessor)
 | 
			
		||||
            .GetMethods()
 | 
			
		||||
            .FirstOrDefault(m => m.Name == nameof(NetPacketProcessor.SubscribeReusable) &&
 | 
			
		||||
                m.GetParameters().Length == 1 &&
 | 
			
		||||
                m.GetParameters()[0].ParameterType.GetGenericTypeDefinition() == typeof(Action<,>)
 | 
			
		||||
            )!;
 | 
			
		||||
 | 
			
		||||
        MethodInfo registerNestedTypeMethod = typeof(NetPacketProcessor)
 | 
			
		||||
            .GetMethods()
 | 
			
		||||
            .FirstOrDefault(m => m.Name == nameof(NetPacketProcessor.RegisterNestedType) &&
 | 
			
		||||
                m.GetParameters().Length == 0
 | 
			
		||||
            )!;
 | 
			
		||||
 | 
			
		||||
        MethodInfo onPacketArrivedMethod = typeof(LiteNetLibCommunicatorBase)
 | 
			
		||||
            .GetMethod(nameof(OnPacketArrived), BindingFlags.NonPublic | BindingFlags.Instance)!;
 | 
			
		||||
 | 
			
		||||
        // Register all network packets by calling the methods bellow where T is our found network packet type
 | 
			
		||||
        // NetPacketProcessor.SubscribeReusable<T, NetPeer>(Action<T, NetPeer> onReceive)
 | 
			
		||||
        // NetPacketProcessor.RegisterNestedType<T>()
 | 
			
		||||
        foreach (Type packetType in packetTypes)
 | 
			
		||||
        {
 | 
			
		||||
            if (!packetType.IsClass)
 | 
			
		||||
            {
 | 
			
		||||
                MethodInfo genericRegisterNestedTypeMethod = registerNestedTypeMethod.MakeGenericMethod(packetType);
 | 
			
		||||
                genericRegisterNestedTypeMethod.Invoke(netPacketProcessor, []);
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            MethodInfo genericOnPacketArrivedMethod = onPacketArrivedMethod.MakeGenericMethod(packetType);
 | 
			
		||||
 | 
			
		||||
            Type delegateType = typeof(Action<,>).MakeGenericType(packetType, typeof(NetPeer));
 | 
			
		||||
            Delegate delegateHandler = Delegate.CreateDelegate(delegateType, this, genericOnPacketArrivedMethod);
 | 
			
		||||
 | 
			
		||||
            var genericSubscribeReusableMethod = subscribeReusableMethod.MakeGenericMethod(packetType, typeof(NetPeer));
 | 
			
		||||
            genericSubscribeReusableMethod.Invoke(netPacketProcessor, [delegateHandler]);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public LiteNetLibCommunicatorBase()
 | 
			
		||||
    {
 | 
			
		||||
        Listener = new EventBasedNetListener();
 | 
			
		||||
        Manager = new NetManager(Listener);
 | 
			
		||||
 | 
			
		||||
        Listener.NetworkReceiveEvent += NetworkReceiveEvent;
 | 
			
		||||
        Listener.PeerConnectedEvent += ConnectionEstablished;
 | 
			
		||||
        Listener.PeerDisconnectedEvent += ConnectionAbolished;
 | 
			
		||||
 | 
			
		||||
        SetupEnginePackets();
 | 
			
		||||
        SetupPackets();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void SetupEnginePackets()
 | 
			
		||||
    {
 | 
			
		||||
        // I know, ugly af. I need to find a better way
 | 
			
		||||
        netPacketProcessor.RegisterNestedType(AABBNetPacker.Write, AABBNetPacker.Read);
 | 
			
		||||
        netPacketProcessor.RegisterNestedType(CircleNetPacker.Write, CircleNetPacker.Read);
 | 
			
		||||
        netPacketProcessor.RegisterNestedType(ColorHSVNetPacker.Write, ColorHSVNetPacker.Read);
 | 
			
		||||
        netPacketProcessor.RegisterNestedType(ColorRGBANetPacker.Write, ColorRGBANetPacker.Read);
 | 
			
		||||
        netPacketProcessor.RegisterNestedType(ColorRGBNetPacker.Write, ColorRGBNetPacker.Read);
 | 
			
		||||
        netPacketProcessor.RegisterNestedType(Line2DEquationNetPacker.Write, Line2DEquationNetPacker.Read);
 | 
			
		||||
        netPacketProcessor.RegisterNestedType(Line2DNetPacker.Write, Line2DNetPacker.Read);
 | 
			
		||||
        netPacketProcessor.RegisterNestedType(Projection1DNetPacker.Write, Projection1DNetPacker.Read);
 | 
			
		||||
        netPacketProcessor.RegisterNestedType(QuaternionNetPacker.Write, QuaternionNetPacker.Read);
 | 
			
		||||
        netPacketProcessor.RegisterNestedType(Shape2DNetPacker.Write, Shape2DNetPacker.Read);
 | 
			
		||||
        netPacketProcessor.RegisterNestedType(TriangleNetPacker.Write, TriangleNetPacker.Read);
 | 
			
		||||
        netPacketProcessor.RegisterNestedType(Vector2DNetPacker.Write, Vector2DNetPacker.Read);
 | 
			
		||||
        netPacketProcessor.RegisterNestedType(Vector3DNetPacker.Write, Vector3DNetPacker.Read);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public INetworkCommunicator SubscribeToPackets<T>(Event<IConnection, T>.EventHandler callback)
 | 
			
		||||
    {
 | 
			
		||||
        Type type = typeof(T);
 | 
			
		||||
        if (!listeners.TryGetValue(type, out Event<IConnection, object>? @event))
 | 
			
		||||
        {
 | 
			
		||||
            @event = new();
 | 
			
		||||
            listeners.Add(type, @event);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @event.AddListener(EventDelegateWrapper(callback));
 | 
			
		||||
        return this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public INetworkCommunicator UnsubscribeFromPackets<T>(Event<IConnection, T>.EventHandler callback)
 | 
			
		||||
    {
 | 
			
		||||
        Type type = typeof(T);
 | 
			
		||||
        if (!listeners.TryGetValue(type, out Event<IConnection, object>? @event))
 | 
			
		||||
            return this;
 | 
			
		||||
 | 
			
		||||
        @event.RemoveListener(EventDelegateWrapper(callback));
 | 
			
		||||
        return this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static Event<IConnection, object>.EventHandler EventDelegateWrapper<T>(Event<IConnection, T>.EventHandler callback) => (sender, @object) => callback.Invoke(sender, (T)@object);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										104
									
								
								Shared/Network/LiteNetLib/LiteNetLibServer.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,104 @@
 | 
			
		||||
using System.Linq;
 | 
			
		||||
 | 
			
		||||
using LiteNetLib;
 | 
			
		||||
using LiteNetLib.Utils;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
using Syntriax.Engine.Core.Debug;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Network;
 | 
			
		||||
 | 
			
		||||
public class LiteNetLibServer : LiteNetLibCommunicatorBase, INetworkCommunicatorServer
 | 
			
		||||
{
 | 
			
		||||
    public string Password { get; private set; } = string.Empty;
 | 
			
		||||
    public int MaxConnectionCount { get; private set; } = 2;
 | 
			
		||||
    public int Port { get; private set; } = 8888;
 | 
			
		||||
 | 
			
		||||
    private readonly NetDataWriter netDataWriter = new();
 | 
			
		||||
 | 
			
		||||
    public LiteNetLibServer() : this(8888, 2) { }
 | 
			
		||||
    public LiteNetLibServer(int port, int maxConnectionCount) : base()
 | 
			
		||||
    {
 | 
			
		||||
        MaxConnectionCount = maxConnectionCount;
 | 
			
		||||
        Port = port;
 | 
			
		||||
 | 
			
		||||
        Listener.ConnectionRequestEvent += OnConnectionRequest;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected override IConnection GetConnection(NetPeer peer) => new LiteNetLibClientConnection(peer);
 | 
			
		||||
 | 
			
		||||
    private void OnConnectionRequest(ConnectionRequest request)
 | 
			
		||||
    {
 | 
			
		||||
        logger?.Log(this, $"Connection request from ip {request.RemoteEndPoint}");
 | 
			
		||||
        logger?.Log(this, $"Current connection count: {Connections.Count}");
 | 
			
		||||
        if (Manager.ConnectedPeersCount < MaxConnectionCount)
 | 
			
		||||
            request.AcceptIfKey(Password);
 | 
			
		||||
        else
 | 
			
		||||
            request.Reject();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public INetworkCommunicatorServer Start(int port, int maxConnectionCount, string? password = null)
 | 
			
		||||
    {
 | 
			
		||||
        if (!UniverseObject.IsInUniverse)
 | 
			
		||||
            throw new($"{nameof(LiteNetLibServer)} must be in an universe to start");
 | 
			
		||||
 | 
			
		||||
        Password = password ?? string.Empty;
 | 
			
		||||
        MaxConnectionCount = maxConnectionCount;
 | 
			
		||||
        Port = port;
 | 
			
		||||
 | 
			
		||||
        logger?.Log(this, $"Starting server on port '{port}' with password '{Password}' and max connection count '{maxConnectionCount}'");
 | 
			
		||||
        logger?.Log(this, $"Server status: {(Manager.Start(port) ? "Active" : "Failed")}");
 | 
			
		||||
 | 
			
		||||
        return this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public INetworkCommunicatorServer SendToClient<T>(IConnection connection, T packet, PacketDelivery packetDelivery) where T : class, new()
 | 
			
		||||
    {
 | 
			
		||||
        netDataWriter.Reset();
 | 
			
		||||
        netPacketProcessor.Write(netDataWriter, packet);
 | 
			
		||||
 | 
			
		||||
        if (Manager.ConnectedPeerList.FirstOrDefault(p => p.Id.CompareTo(connection.Id) == 0) is not NetPeer netPeer)
 | 
			
		||||
            throw new($"Peer {connection} couldn't be found.");
 | 
			
		||||
 | 
			
		||||
        switch (packetDelivery)
 | 
			
		||||
        {
 | 
			
		||||
            case PacketDelivery.ReliableInOrder: netPeer.Send(netDataWriter, DeliveryMethod.ReliableOrdered); break;
 | 
			
		||||
            case PacketDelivery.UnreliableInOrder: netPeer.Send(netDataWriter, DeliveryMethod.Sequenced); break;
 | 
			
		||||
            case PacketDelivery.ReliableOutOfOrder: netPeer.Send(netDataWriter, DeliveryMethod.ReliableUnordered); break;
 | 
			
		||||
            case PacketDelivery.UnreliableOutOfOrder: netPeer.Send(netDataWriter, DeliveryMethod.Unreliable); break;
 | 
			
		||||
            default: netPeer.Send(netDataWriter, DeliveryMethod.ReliableOrdered); break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public INetworkCommunicatorServer SendToAll<T>(T packet, PacketDelivery packetDelivery) where T : class, new()
 | 
			
		||||
    {
 | 
			
		||||
        netDataWriter.Reset();
 | 
			
		||||
        netPacketProcessor.Write(netDataWriter, packet);
 | 
			
		||||
 | 
			
		||||
        switch (packetDelivery)
 | 
			
		||||
        {
 | 
			
		||||
            case PacketDelivery.ReliableInOrder: Manager.SendToAll(netDataWriter, DeliveryMethod.ReliableOrdered); break;
 | 
			
		||||
            case PacketDelivery.UnreliableInOrder: Manager.SendToAll(netDataWriter, DeliveryMethod.Sequenced); break;
 | 
			
		||||
            case PacketDelivery.ReliableOutOfOrder: Manager.SendToAll(netDataWriter, DeliveryMethod.ReliableUnordered); break;
 | 
			
		||||
            case PacketDelivery.UnreliableOutOfOrder: Manager.SendToAll(netDataWriter, DeliveryMethod.Unreliable); break;
 | 
			
		||||
            default: Manager.SendToAll(netDataWriter, DeliveryMethod.ReliableOrdered); break;
 | 
			
		||||
        }
 | 
			
		||||
        return this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void PollEvents(IUniverse sender, IUniverse.UpdateArguments args) => Manager.PollEvents();
 | 
			
		||||
 | 
			
		||||
    protected override void OnEnteredUniverse(IUniverse universe)
 | 
			
		||||
    {
 | 
			
		||||
        base.OnEnteredUniverse(universe);
 | 
			
		||||
        universe.OnPostUpdate.AddListener(PollEvents);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected override void OnExitedUniverse(IUniverse universe)
 | 
			
		||||
    {
 | 
			
		||||
        base.OnExitedUniverse(universe);
 | 
			
		||||
        universe.OnPostUpdate.RemoveListener(PollEvents);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										16
									
								
								Shared/Network/LiteNetLib/LiteNetLibServerConnection.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,16 @@
 | 
			
		||||
using LiteNetLib;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Network;
 | 
			
		||||
 | 
			
		||||
public record class LiteNetLibServerConnection(NetPeer NetPeer) : IConnection
 | 
			
		||||
{
 | 
			
		||||
    public string Id => NetPeer.RemoteId.ToString();
 | 
			
		||||
 | 
			
		||||
    public float Ping => NetPeer.Ping * .001f;
 | 
			
		||||
    public float RoundTrip => NetPeer.RoundTripTime * .001f;
 | 
			
		||||
 | 
			
		||||
    public int PingMs => NetPeer.Ping;
 | 
			
		||||
    public int RoundTripMs => NetPeer.RoundTripTime;
 | 
			
		||||
 | 
			
		||||
    public override string ToString() => $"Connection({Id})";
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										22
									
								
								Shared/Network/LiteNetLib/Packers/AABBNetPacker.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,22 @@
 | 
			
		||||
using LiteNetLib.Utils;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Network;
 | 
			
		||||
 | 
			
		||||
internal static class AABBNetPacker
 | 
			
		||||
{
 | 
			
		||||
    internal static void Write(NetDataWriter writer, AABB data)
 | 
			
		||||
    {
 | 
			
		||||
        Vector2DNetPacker.Write(writer, data.LowerBoundary);
 | 
			
		||||
        Vector2DNetPacker.Write(writer, data.UpperBoundary);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    internal static AABB Read(NetDataReader reader)
 | 
			
		||||
    {
 | 
			
		||||
        Vector2D lowerBoundary = Vector2DNetPacker.Read(reader);
 | 
			
		||||
        Vector2D upperBoundary = Vector2DNetPacker.Read(reader);
 | 
			
		||||
 | 
			
		||||
        return new AABB(lowerBoundary, upperBoundary);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										22
									
								
								Shared/Network/LiteNetLib/Packers/CircleNetPacker.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,22 @@
 | 
			
		||||
using LiteNetLib.Utils;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Network;
 | 
			
		||||
 | 
			
		||||
internal static class CircleNetPacker
 | 
			
		||||
{
 | 
			
		||||
    internal static void Write(NetDataWriter writer, Circle data)
 | 
			
		||||
    {
 | 
			
		||||
        Vector2DNetPacker.Write(writer, data.Center);
 | 
			
		||||
        writer.Put(data.Radius);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    internal static Circle Read(NetDataReader reader)
 | 
			
		||||
    {
 | 
			
		||||
        Vector2D center = Vector2DNetPacker.Read(reader);
 | 
			
		||||
        float radius = reader.GetFloat();
 | 
			
		||||
 | 
			
		||||
        return new Circle(center, radius);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										24
									
								
								Shared/Network/LiteNetLib/Packers/ColorHSVNetPacker.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,24 @@
 | 
			
		||||
using LiteNetLib.Utils;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Network;
 | 
			
		||||
 | 
			
		||||
internal static class ColorHSVNetPacker
 | 
			
		||||
{
 | 
			
		||||
    internal static void Write(NetDataWriter writer, ColorHSV data)
 | 
			
		||||
    {
 | 
			
		||||
        writer.Put(data.Hue);
 | 
			
		||||
        writer.Put(data.Saturation);
 | 
			
		||||
        writer.Put(data.Value);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    internal static ColorHSV Read(NetDataReader reader)
 | 
			
		||||
    {
 | 
			
		||||
        float hue = reader.GetFloat();
 | 
			
		||||
        float saturation = reader.GetFloat();
 | 
			
		||||
        float value = reader.GetFloat();
 | 
			
		||||
 | 
			
		||||
        return new ColorHSV(hue, saturation, value);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										26
									
								
								Shared/Network/LiteNetLib/Packers/ColorRGBANetPacker.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,26 @@
 | 
			
		||||
using LiteNetLib.Utils;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Network;
 | 
			
		||||
 | 
			
		||||
internal static class ColorRGBANetPacker
 | 
			
		||||
{
 | 
			
		||||
    internal static void Write(NetDataWriter writer, ColorRGBA data)
 | 
			
		||||
    {
 | 
			
		||||
        writer.Put(data.R);
 | 
			
		||||
        writer.Put(data.G);
 | 
			
		||||
        writer.Put(data.B);
 | 
			
		||||
        writer.Put(data.A);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    internal static ColorRGBA Read(NetDataReader reader)
 | 
			
		||||
    {
 | 
			
		||||
        byte red = reader.GetByte();
 | 
			
		||||
        byte green = reader.GetByte();
 | 
			
		||||
        byte blue = reader.GetByte();
 | 
			
		||||
        byte alpha = reader.GetByte();
 | 
			
		||||
 | 
			
		||||
        return new ColorRGBA(red, green, blue, alpha);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										24
									
								
								Shared/Network/LiteNetLib/Packers/ColorRGBNetPacker.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,24 @@
 | 
			
		||||
using LiteNetLib.Utils;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Network;
 | 
			
		||||
 | 
			
		||||
internal static class ColorRGBNetPacker
 | 
			
		||||
{
 | 
			
		||||
    internal static void Write(NetDataWriter writer, ColorRGB data)
 | 
			
		||||
    {
 | 
			
		||||
        writer.Put(data.R);
 | 
			
		||||
        writer.Put(data.G);
 | 
			
		||||
        writer.Put(data.B);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    internal static ColorRGB Read(NetDataReader reader)
 | 
			
		||||
    {
 | 
			
		||||
        byte red = reader.GetByte();
 | 
			
		||||
        byte green = reader.GetByte();
 | 
			
		||||
        byte blue = reader.GetByte();
 | 
			
		||||
 | 
			
		||||
        return new ColorRGB(red, green, blue);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										22
									
								
								Shared/Network/LiteNetLib/Packers/Line2DEquationNetPacker.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,22 @@
 | 
			
		||||
using LiteNetLib.Utils;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Network;
 | 
			
		||||
 | 
			
		||||
internal static class Line2DEquationNetPacker
 | 
			
		||||
{
 | 
			
		||||
    internal static void Write(NetDataWriter writer, Line2DEquation data)
 | 
			
		||||
    {
 | 
			
		||||
        writer.Put(data.Slope);
 | 
			
		||||
        writer.Put(data.OffsetY);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    internal static Line2DEquation Read(NetDataReader reader)
 | 
			
		||||
    {
 | 
			
		||||
        float slope = reader.GetFloat();
 | 
			
		||||
        float offsetY = reader.GetFloat();
 | 
			
		||||
 | 
			
		||||
        return new Line2DEquation(slope, offsetY);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										22
									
								
								Shared/Network/LiteNetLib/Packers/Line2DNetPacker.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,22 @@
 | 
			
		||||
using LiteNetLib.Utils;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Network;
 | 
			
		||||
 | 
			
		||||
internal static class Line2DNetPacker
 | 
			
		||||
{
 | 
			
		||||
    internal static void Write(NetDataWriter writer, Line2D data)
 | 
			
		||||
    {
 | 
			
		||||
        Vector2DNetPacker.Write(writer, data.From);
 | 
			
		||||
        Vector2DNetPacker.Write(writer, data.To);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    internal static Line2D Read(NetDataReader reader)
 | 
			
		||||
    {
 | 
			
		||||
        Vector2D from = Vector2DNetPacker.Read(reader);
 | 
			
		||||
        Vector2D to = Vector2DNetPacker.Read(reader);
 | 
			
		||||
 | 
			
		||||
        return new Line2D(from, to);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										22
									
								
								Shared/Network/LiteNetLib/Packers/Projection1DNetPacker.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,22 @@
 | 
			
		||||
using LiteNetLib.Utils;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Network;
 | 
			
		||||
 | 
			
		||||
internal static class Projection1DNetPacker
 | 
			
		||||
{
 | 
			
		||||
    internal static void Write(NetDataWriter writer, Projection1D data)
 | 
			
		||||
    {
 | 
			
		||||
        writer.Put(data.Min);
 | 
			
		||||
        writer.Put(data.Max);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    internal static Projection1D Read(NetDataReader reader)
 | 
			
		||||
    {
 | 
			
		||||
        float min = reader.GetFloat();
 | 
			
		||||
        float max = reader.GetFloat();
 | 
			
		||||
 | 
			
		||||
        return new Projection1D(min, max);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										26
									
								
								Shared/Network/LiteNetLib/Packers/QuaternionNetPacker.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,26 @@
 | 
			
		||||
using LiteNetLib.Utils;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Network;
 | 
			
		||||
 | 
			
		||||
internal static class QuaternionNetPacker
 | 
			
		||||
{
 | 
			
		||||
    internal static void Write(NetDataWriter writer, Quaternion data)
 | 
			
		||||
    {
 | 
			
		||||
        writer.Put(data.X);
 | 
			
		||||
        writer.Put(data.Y);
 | 
			
		||||
        writer.Put(data.Z);
 | 
			
		||||
        writer.Put(data.W);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    internal static Quaternion Read(NetDataReader reader)
 | 
			
		||||
    {
 | 
			
		||||
        float x = reader.GetFloat();
 | 
			
		||||
        float y = reader.GetFloat();
 | 
			
		||||
        float z = reader.GetFloat();
 | 
			
		||||
        float w = reader.GetFloat();
 | 
			
		||||
 | 
			
		||||
        return new Quaternion(x, y, z, w);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										28
									
								
								Shared/Network/LiteNetLib/Packers/Shape2DNetPacker.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,28 @@
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
 | 
			
		||||
using LiteNetLib.Utils;
 | 
			
		||||
 | 
			
		||||
using Syntriax.Engine.Core;
 | 
			
		||||
 | 
			
		||||
namespace Syntriax.Engine.Network;
 | 
			
		||||
 | 
			
		||||
internal static class Shape2DNetPacker
 | 
			
		||||
{
 | 
			
		||||
    internal static void Write(NetDataWriter writer, Shape2D data)
 | 
			
		||||
    {
 | 
			
		||||
        writer.Put(data.Vertices.Count);
 | 
			
		||||
        foreach (Vector2D vertex in data.Vertices)
 | 
			
		||||
            Vector2DNetPacker.Write(writer, vertex);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    internal static Shape2D Read(NetDataReader reader)
 | 
			
		||||
    {
 | 
			
		||||
        int verticesCount = reader.GetInt();
 | 
			
		||||
        List<Vector2D> vertices = new(verticesCount);
 | 
			
		||||
 | 
			
		||||
        for (int i = 0; i < verticesCount; i++)
 | 
			
		||||
            vertices.Add(Vector2DNetPacker.Read(reader));
 | 
			
		||||
 | 
			
		||||
        return new Shape2D(vertices);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||