├── .gitattributes
├── .gitignore
├── CreateTable.sql
├── Deploy
├── Extract DarkRiftServer.rar here.txt
├── Levels
│ └── Act1.nav
├── MasterServerExample.config
└── WorldServer.config
├── LICENSE
├── README.md
├── RecastDetour
├── Detour
│ ├── DetourCommon.cs
│ ├── DetourNavMesh.cs
│ ├── DetourNavMeshBuilder.cs
│ ├── DetourNavMeshQuery.cs
│ ├── DetourNode.cs
│ ├── DetourStatus.cs
│ ├── NavMesh.cs
│ ├── NavMeshCreateParams.cs
│ └── NavMeshQuery.cs
├── NavMeshAgent.cs
├── NavMeshSerializer.cs
├── Pathfinder.cs
├── Properties
│ └── AssemblyInfo.cs
├── Recast
│ ├── BuildContext.cs
│ ├── Recast.cs
│ ├── RecastArea.cs
│ ├── RecastContour.cs
│ ├── RecastFilter.cs
│ ├── RecastLayers.cs
│ ├── RecastMesh.cs
│ ├── RecastMeshDetail.cs
│ ├── RecastRasterization.cs
│ └── RecastRegion.cs
├── RecastDetour.csproj
└── packages.config
├── ServerPlugins
├── Authentication
│ ├── AuthenticationPlugin.cs
│ └── EncryptionData.cs
├── Database
│ ├── MySQLPlugin.cs
│ ├── PasswordResetData.cs
│ └── SqlAccountData.cs
├── Game
│ ├── Components
│ │ ├── BuffComponent.cs
│ │ ├── Component.cs
│ │ ├── NavigationComponent.cs
│ │ └── SpawnComponent.cs
│ ├── Entities
│ │ ├── Entity.cs
│ │ ├── Monster.cs
│ │ └── Player.cs
│ ├── GamePlugin.cs
│ └── Levels
│ │ └── Act1.nav
├── Mail
│ └── MailPlugin.cs
├── Properties
│ └── AssemblyInfo.cs
├── Room
│ └── RoomPlugin.cs
├── RoomHandler
│ ├── RegisteredRoom.cs
│ └── RoomHandlerPlugin.cs
├── ServerPluginBase.cs
├── ServerPlugins.csproj
├── SpawnerHandler
│ ├── RegisteredSpawner.cs
│ ├── SpawnTask.cs
│ └── SpawnerHandlerPlugin.cs
├── Time
│ └── TimePlugin.cs
├── app.config
└── packages.config
├── Spawner
├── Properties
│ ├── AssemblyInfo.cs
│ ├── Settings.Designer.cs
│ └── Settings.settings
├── Spawner.csproj
├── SpawnerClient.cs
├── SpawnerOptions.cs
└── app.config
├── TundraClientExample
├── MonoBehaviourExample.cs
├── Properties
│ └── AssemblyInfo.cs
└── TundraClient.csproj
├── TundraServerPlugins.sln
└── Utils
├── ArgNames.cs
├── Conversion
├── BigEndianBitConverter.cs
├── DoubleConverter.cs
├── EndianBitConverter.cs
├── Endianness.cs
└── LittleEndianBitConverter.cs
├── EntityState.cs
├── Extensions
└── SerializationExtensions.cs
├── Game
└── TundraVector3.cs
├── IO
├── EndianBinaryReader.cs
└── EndianBinaryWriter.cs
├── MessageTags.cs
├── Messages
├── NotificationMessage.cs
├── Notifications
│ ├── ProcessKilledMessage .cs
│ └── SpawnFinalizedMessage.cs
├── RequestMessage.cs
├── Requests
│ ├── ConfirmEmailMessage.cs
│ ├── RegisterSpawnedProcessMessage.cs
│ ├── RequestFromUserMessage.cs
│ └── ResetPasswordMessage.cs
├── ResponseMessage.cs
└── Responses
│ ├── ClientSpawnSuccessMessage.cs
│ ├── FailedMessage.cs
│ ├── LoginSuccessMessage.cs
│ ├── RegisterRoomSuccessMessage.cs
│ ├── RegisterSpawnerSuccessMessage.cs
│ ├── SpawnFromMasterToSpawnerFailedMessage.cs
│ └── SpawnFromMasterToSpawnerSuccessMessage.cs
├── NetworkEntity.cs
├── Packets
├── AckNavigateToPacket.cs
├── BytePacket.cs
├── BytesPacket.cs
├── ChangStatePacket.cs
├── EntityPacket.cs
├── FloatPacket.cs
├── GameInfoPacket.cs
├── IntPacket.cs
├── KillSpawnedProcessPacket.cs
├── NavigateToPacket.cs
├── PlayerLeftRoomPacket.cs
├── PositionPacket.cs
├── RoomAccessPacket.cs
├── RoomAccessProvideCheckPacket.cs
├── RoomAccessRequestPacket.cs
├── RoomAccessValidatePacket.cs
├── RoomAccessValidatedPacket.cs
├── SaveRoomOptionsPacket.cs
├── SpawnRequestPacket.cs
├── SpawnStatusPacket.cs
├── StringPacket.cs
└── UsernameAndPeerIdPacket.cs
├── Properties
└── AssemblyInfo.cs
├── ResponseStatus.cs
├── RoomOptions.cs
├── Security.cs
├── SmoothPath.cs
├── SpawnStatus.cs
├── SpawnerOptions.cs
├── Utils.csproj
├── WorldOptions.cs
└── packages.config
/.gitattributes:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # Set default behavior to automatically normalize line endings.
3 | ###############################################################################
4 | * text=auto
5 |
6 | ###############################################################################
7 | # Set default behavior for command prompt diff.
8 | #
9 | # This is need for earlier builds of msysgit that does not have it on by
10 | # default for csharp files.
11 | # Note: This is only used by command line
12 | ###############################################################################
13 | #*.cs diff=csharp
14 |
15 | ###############################################################################
16 | # Set the merge driver for project and solution files
17 | #
18 | # Merging from the command prompt will add diff markers to the files if there
19 | # are conflicts (Merging from VS is not affected by the settings below, in VS
20 | # the diff markers are never inserted). Diff markers may cause the following
21 | # file extensions to fail to load in VS. An alternative would be to treat
22 | # these files as binary and thus will always conflict and require user
23 | # intervention with every merge. To do so, just uncomment the entries below
24 | ###############################################################################
25 | #*.sln merge=binary
26 | #*.csproj merge=binary
27 | #*.vbproj merge=binary
28 | #*.vcxproj merge=binary
29 | #*.vcproj merge=binary
30 | #*.dbproj merge=binary
31 | #*.fsproj merge=binary
32 | #*.lsproj merge=binary
33 | #*.wixproj merge=binary
34 | #*.modelproj merge=binary
35 | #*.sqlproj merge=binary
36 | #*.wwaproj merge=binary
37 |
38 | ###############################################################################
39 | # behavior for image files
40 | #
41 | # image files are treated as binary by default.
42 | ###############################################################################
43 | #*.jpg binary
44 | #*.png binary
45 | #*.gif binary
46 |
47 | ###############################################################################
48 | # diff behavior for common document formats
49 | #
50 | # Convert binary document formats to text before diffing them. This feature
51 | # is only available from the command line. Turn it on by uncommenting the
52 | # entries below.
53 | ###############################################################################
54 | #*.doc diff=astextplain
55 | #*.DOC diff=astextplain
56 | #*.docx diff=astextplain
57 | #*.DOCX diff=astextplain
58 | #*.dot diff=astextplain
59 | #*.DOT diff=astextplain
60 | #*.pdf diff=astextplain
61 | #*.PDF diff=astextplain
62 | #*.rtf diff=astextplain
63 | #*.RTF diff=astextplain
64 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.userosscache
8 | *.sln.docstates
9 |
10 | # User-specific files (MonoDevelop/Xamarin Studio)
11 | *.userprefs
12 |
13 | # Build results
14 | [Dd]ebug/
15 | [Dd]ebugPublic/
16 | [Rr]elease/
17 | [Rr]eleases/
18 | x64/
19 | x86/
20 | bld/
21 | [Bb]in/
22 | [Oo]bj/
23 | [Ll]og/
24 |
25 | # Visual Studio 2015 cache/options directory
26 | .vs/
27 | # Uncomment if you have tasks that create the project's static files in wwwroot
28 | #wwwroot/
29 |
30 | # MSTest test Results
31 | [Tt]est[Rr]esult*/
32 | [Bb]uild[Ll]og.*
33 |
34 | # NUNIT
35 | *.VisualState.xml
36 | TestResult.xml
37 |
38 | # Build Results of an ATL Project
39 | [Dd]ebugPS/
40 | [Rr]eleasePS/
41 | dlldata.c
42 |
43 | # DNX
44 | project.lock.json
45 | project.fragment.lock.json
46 | artifacts/
47 |
48 | *_i.c
49 | *_p.c
50 | *_i.h
51 | *.ilk
52 | *.meta
53 | *.obj
54 | *.pch
55 | *.pdb
56 | *.pgc
57 | *.pgd
58 | *.rsp
59 | *.sbr
60 | *.tlb
61 | *.tli
62 | *.tlh
63 | *.tmp
64 | *.tmp_proj
65 | *.log
66 | *.vspscc
67 | *.vssscc
68 | .builds
69 | *.pidb
70 | *.svclog
71 | *.scc
72 |
73 | # Chutzpah Test files
74 | _Chutzpah*
75 |
76 | # Visual C++ cache files
77 | ipch/
78 | *.aps
79 | *.ncb
80 | *.opendb
81 | *.opensdf
82 | *.sdf
83 | *.cachefile
84 | *.VC.db
85 | *.VC.VC.opendb
86 |
87 | # Visual Studio profiler
88 | *.psess
89 | *.vsp
90 | *.vspx
91 | *.sap
92 |
93 | # TFS 2012 Local Workspace
94 | $tf/
95 |
96 | # Guidance Automation Toolkit
97 | *.gpState
98 |
99 | # ReSharper is a .NET coding add-in
100 | _ReSharper*/
101 | *.[Rr]e[Ss]harper
102 | *.DotSettings.user
103 |
104 | # JustCode is a .NET coding add-in
105 | .JustCode
106 |
107 | # TeamCity is a build add-in
108 | _TeamCity*
109 |
110 | # DotCover is a Code Coverage Tool
111 | *.dotCover
112 |
113 | # NCrunch
114 | _NCrunch_*
115 | .*crunch*.local.xml
116 | nCrunchTemp_*
117 |
118 | # MightyMoose
119 | *.mm.*
120 | AutoTest.Net/
121 |
122 | # Web workbench (sass)
123 | .sass-cache/
124 |
125 | # Installshield output folder
126 | [Ee]xpress/
127 |
128 | # DocProject is a documentation generator add-in
129 | DocProject/buildhelp/
130 | DocProject/Help/*.HxT
131 | DocProject/Help/*.HxC
132 | DocProject/Help/*.hhc
133 | DocProject/Help/*.hhk
134 | DocProject/Help/*.hhp
135 | DocProject/Help/Html2
136 | DocProject/Help/html
137 |
138 | # Click-Once directory
139 | publish/
140 |
141 | # Publish Web Output
142 | *.[Pp]ublish.xml
143 | *.azurePubxml
144 | # TODO: Comment the next line if you want to checkin your web deploy settings
145 | # but database connection strings (with potential passwords) will be unencrypted
146 | #*.pubxml
147 | *.publishproj
148 |
149 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
150 | # checkin your Azure Web App publish settings, but sensitive information contained
151 | # in these scripts will be unencrypted
152 | PublishScripts/
153 |
154 | # NuGet Packages
155 | *.nupkg
156 | # The packages folder can be ignored because of Package Restore
157 | **/packages/*
158 | # except build/, which is used as an MSBuild target.
159 | !**/packages/build/
160 | # Uncomment if necessary however generally it will be regenerated when needed
161 | #!**/packages/repositories.config
162 | # NuGet v3's project.json files produces more ignoreable files
163 | *.nuget.props
164 | *.nuget.targets
165 |
166 | # Microsoft Azure Build Output
167 | csx/
168 | *.build.csdef
169 |
170 | # Microsoft Azure Emulator
171 | ecf/
172 | rcf/
173 |
174 | # Windows Store app package directories and files
175 | AppPackages/
176 | BundleArtifacts/
177 | Package.StoreAssociation.xml
178 | _pkginfo.txt
179 |
180 | # Visual Studio cache files
181 | # files ending in .cache can be ignored
182 | *.[Cc]ache
183 | # but keep track of directories ending in .cache
184 | !*.[Cc]ache/
185 |
186 | # Others
187 | ClientBin/
188 | ~$*
189 | *~
190 | *.dbmdl
191 | *.dbproj.schemaview
192 | *.jfm
193 | *.pfx
194 | *.publishsettings
195 | node_modules/
196 | orleans.codegen.cs
197 |
198 | # Since there are multiple workflows, uncomment next line to ignore bower_components
199 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
200 | #bower_components/
201 |
202 | # RIA/Silverlight projects
203 | Generated_Code/
204 |
205 | # Backup & report files from converting an old project file
206 | # to a newer Visual Studio version. Backup files are not needed,
207 | # because we have git ;-)
208 | _UpgradeReport_Files/
209 | Backup*/
210 | UpgradeLog*.XML
211 | UpgradeLog*.htm
212 |
213 | # SQL Server files
214 | *.mdf
215 | *.ldf
216 |
217 | # Business Intelligence projects
218 | *.rdl.data
219 | *.bim.layout
220 | *.bim_*.settings
221 |
222 | # Microsoft Fakes
223 | FakesAssemblies/
224 |
225 | # GhostDoc plugin setting file
226 | *.GhostDoc.xml
227 |
228 | # Node.js Tools for Visual Studio
229 | .ntvs_analysis.dat
230 |
231 | # Visual Studio 6 build log
232 | *.plg
233 |
234 | # Visual Studio 6 workspace options file
235 | *.opt
236 |
237 | # Visual Studio LightSwitch build output
238 | **/*.HTMLClient/GeneratedArtifacts
239 | **/*.DesktopClient/GeneratedArtifacts
240 | **/*.DesktopClient/ModelManifest.xml
241 | **/*.Server/GeneratedArtifacts
242 | **/*.Server/ModelManifest.xml
243 | _Pvt_Extensions
244 |
245 | # Paket dependency manager
246 | .paket/paket.exe
247 | paket-files/
248 |
249 | # FAKE - F# Make
250 | .fake/
251 |
252 | # JetBrains Rider
253 | .idea/
254 | *.sln.iml
255 |
256 | # CodeRush
257 | .cr/
258 |
259 | # Python Tools for Visual Studio (PTVS)
260 | __pycache__/
261 | *.pyc
262 |
263 | /Deploy/WorldPlugins
264 | /Deploy/Plugins
265 | /Deploy/Data
266 | /Deploy/Logs
267 | /Deploy/Server.config
268 | /Deploy/DarkRift.Server.Console.exe.config
269 | /Deploy/DarkRift.Server.Console.exe
270 | /Lib
271 | /Deploy/Lib
272 | /Deploy/DarkRift.Server.dll
273 | /Deploy/DarkRift.dll
274 | /Deploy/DarkRift.Client.dll
275 | /Deploy/WorldPlugins.dll
276 | /Deploy/Utils.dll
277 | /Deploy/Spawner.exe.config
278 | /Deploy/Spawner.exe
279 | /Deploy/WorldData
280 | /Deploy/WorldLogs
281 | /ServerPlugins/docs
282 | /Deploy/WorldLogs/
283 | /Deploy/Lib/DarkRift.Server.dll
284 | /Deploy/Lib/DarkRift.dll
285 | /Deploy/Lib/DarkRift.Client.dll
286 |
--------------------------------------------------------------------------------
/CreateTable.sql:
--------------------------------------------------------------------------------
1 | /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
2 | /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
3 | /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
4 | /*!40101 SET NAMES utf8 */;
5 | /*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
6 | /*!40103 SET TIME_ZONE='+00:00' */;
7 | /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
8 | /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
9 | /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
10 | /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
11 |
12 | --
13 | -- Table structure for table `account_properties`
14 | --
15 |
16 | DROP TABLE IF EXISTS `account_properties`;
17 | /*!40101 SET @saved_cs_client = @@character_set_client */;
18 | /*!40101 SET character_set_client = utf8 */;
19 | CREATE TABLE `account_properties` (
20 | `account_property_id` int(11) NOT NULL AUTO_INCREMENT,
21 | `account_id` int(11) NOT NULL,
22 | `prop_key` varchar(45) DEFAULT NULL,
23 | `prop_val` varchar(300) DEFAULT NULL,
24 | PRIMARY KEY (`account_property_id`),
25 | KEY `fk_account_properties_accounts_idx` (`account_id`),
26 | CONSTRAINT `fk_account_properties_accounts` FOREIGN KEY (`account_id`) REFERENCES `accounts` (`account_id`) ON DELETE NO ACTION ON UPDATE NO ACTION
27 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
28 | /*!40101 SET character_set_client = @saved_cs_client */;
29 |
30 | --
31 | -- Table structure for table `accounts`
32 | --
33 |
34 | DROP TABLE IF EXISTS `accounts`;
35 | /*!40101 SET @saved_cs_client = @@character_set_client */;
36 | /*!40101 SET character_set_client = utf8 */;
37 | CREATE TABLE `accounts` (
38 | `account_id` int(11) NOT NULL AUTO_INCREMENT,
39 | `email` varchar(125) DEFAULT NULL,
40 | `password` varchar(125) DEFAULT NULL,
41 | `token` varchar(125) DEFAULT NULL,
42 | `is_admin` tinyint(1) DEFAULT NULL,
43 | `is_guest` tinyint(1) DEFAULT NULL,
44 | `is_email_confirmed` tinyint(1) DEFAULT NULL,
45 | PRIMARY KEY (`account_id`),
46 | UNIQUE KEY `email_UNIQUE` (`email`)
47 | ) ENGINE=InnoDB AUTO_INCREMENT=31 DEFAULT CHARSET=utf8;
48 | /*!40101 SET character_set_client = @saved_cs_client */;
49 |
50 | --
51 | -- Table structure for table `email_confirmation_codes`
52 | --
53 |
54 | DROP TABLE IF EXISTS `email_confirmation_codes`;
55 | /*!40101 SET @saved_cs_client = @@character_set_client */;
56 | /*!40101 SET character_set_client = utf8 */;
57 | CREATE TABLE `email_confirmation_codes` (
58 | `email` varchar(125) NOT NULL,
59 | `code` varchar(45) DEFAULT NULL,
60 | PRIMARY KEY (`email`)
61 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
62 | /*!40101 SET character_set_client = @saved_cs_client */;
63 |
64 | --
65 | -- Table structure for table `password_reset_codes`
66 | --
67 |
68 | DROP TABLE IF EXISTS `password_reset_codes`;
69 | /*!40101 SET @saved_cs_client = @@character_set_client */;
70 | /*!40101 SET character_set_client = utf8 */;
71 | CREATE TABLE `password_reset_codes` (
72 | `email` varchar(125) NOT NULL,
73 | `code` varchar(45) DEFAULT NULL,
74 | PRIMARY KEY (`email`)
75 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
76 | /*!40101 SET character_set_client = @saved_cs_client */;
77 |
78 | --
79 | -- Table structure for table `profile_values`
80 | --
81 |
82 | DROP TABLE IF EXISTS `profile_values`;
83 | /*!40101 SET @saved_cs_client = @@character_set_client */;
84 | /*!40101 SET character_set_client = utf8 */;
85 | CREATE TABLE `profile_values` (
86 | `account_id` int(11) NOT NULL,
87 | `value_key` int(11) NOT NULL,
88 | `value_value` text,
89 | PRIMARY KEY (`account_id`,`value_key`),
90 | KEY `fk_profile_values_accounts1_idx` (`account_id`),
91 | CONSTRAINT `fk_profile_values_accounts1` FOREIGN KEY (`account_id`) REFERENCES `accounts` (`account_id`) ON DELETE NO ACTION ON UPDATE NO ACTION
92 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
93 | /*!40101 SET character_set_client = @saved_cs_client */;
94 | /*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
95 |
96 | /*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
97 | /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
98 | /*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
99 | /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
100 | /*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
101 | /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
102 | /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
103 |
--------------------------------------------------------------------------------
/Deploy/Extract DarkRiftServer.rar here.txt:
--------------------------------------------------------------------------------
1 | Files:
2 |
3 | Lib/
4 | DarkRift.Server.Console.exe
5 | DarkRift.Server.Console.exe.config
6 | Server.config
--------------------------------------------------------------------------------
/Deploy/MasterServerExample.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
12 |
13 |
14 |
23 |
24 |
25 |
26 |
27 |
28 |
31 |
32 |
41 |
42 |
54 |
55 |
56 |
57 |
58 |
65 |
66 |
67 |
74 |
75 |
76 |
77 |
78 |
95 |
96 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
120 |
121 |
122 |
133 |
134 |
135 |
136 |
137 |
--------------------------------------------------------------------------------
/Deploy/WorldServer.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
12 |
13 |
14 |
23 |
24 |
25 |
26 |
27 |
28 |
31 |
32 |
41 |
42 |
54 |
55 |
56 |
57 |
58 |
65 |
66 |
67 |
74 |
75 |
76 |
77 |
78 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
112 |
113 |
114 |
125 |
126 |
127 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 proepkes
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## Obsolete
2 | As https://github.com/proepkes/SpeedDate is now open for public, this repository is rendered obsolete.
3 |
4 | # MSF-DarkRiftServer
5 |
6 | [](https://discord.gg/F9hJhcX)
7 |
8 | ### Highlevel-view:
9 |
10 | [](https://i.imgur.com/x4XIuvF.png)
11 |
12 | ### Instructions:
13 |
14 | 1. Extract "DarkRift Server.rar" into the directory "Deploy"
15 | 1. Copy DarkRiftClient.dll into the directory "Deploy/Lib"
16 | 1. Open "TundraServerPlugins.sln" in Visual Studio
17 | 1. Right-click on solution -> "Restore NuGet-Packages"
18 | 1. Check whether the settings in "Settings.settings" in the Project "Spawner" fit your needs
19 | 1. Right-click on Utils-Project -> "Properties" (last entry) -> select Build Events (on the left) and edit the xcopy-command so it copies the files into your Unity\Assets-directory
20 | 1. Build solution
21 | 1. Replace the contents of "Server.config" with the contents of "MasterServerExample.config" and configure accordingly
22 | 1. Run DarkRift.Server.Console.exe and then run Spawner.exe
23 |
24 | ### FAQ:
25 |
26 | Deploying on Linux results in "System.ArgumentException: An item with the same key has already been added":
27 | - Delete DarkRiftServer.dll from Plugins/
28 |
29 | ### Resources:
30 |
31 | https://darkriftnetworking.com/
32 |
33 | https://github.com/alvyxaz/barebones-masterserver
34 |
35 | ### Warning:
36 |
37 | Even though this project is programmed with great care, I take no responsibility for any (security) issues.
38 |
39 | ### Patron
40 | [](https://www.patreon.com/proepkes)
41 |
--------------------------------------------------------------------------------
/RecastDetour/Detour/DetourNavMesh.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | /**
4 | @typedef dtPolyRef
5 | @par
6 |
7 | Polygon references are subject to the same invalidate/preserve/restore
8 | rules that apply to #dtTileRef's. If the #dtTileRef for the polygon's
9 | tile changes, the polygon reference becomes invalid.
10 |
11 | Changing a polygon's flags, area id, etc. does not impact its polygon
12 | reference.
13 |
14 | @typedef dtTileRef
15 | @par
16 |
17 | The following changes will invalidate a tile reference:
18 |
19 | - The referenced tile has been removed from the navigation mesh.
20 | - The navigation mesh has been initialized using a different set
21 | of #dtNavMeshParams.
22 |
23 | A tile reference is preserved/restored if the tile is added to a navigation
24 | mesh initialized with the original #dtNavMeshParams and is added at the
25 | original reference location. (E.g. The lastRef parameter is used with
26 | dtNavMesh::addTile.)
27 |
28 | Basically, if the storage structure of a tile changes, its associated
29 | tile reference changes.
30 | */
31 |
32 | #if DT_POLYREF64
33 | using dtPolyRef = System.UInt64;
34 | using dtTileRef = System.UInt64;
35 | #else
36 | #endif
37 |
38 | #if DT_POLYREF64
39 | public static partial class Detour{
40 | static const uint DT_SALT_BITS = 16;
41 | static const uint DT_TILE_BITS = 28;
42 | static const uint DT_POLY_BITS = 20;
43 | }
44 | #endif
45 |
46 | namespace RecastDetour.Detour
47 | {
48 | public static partial class Detour{
49 | public static bool overlapSlabs(float[] amin, float[] amax,
50 | float[] bmin,float[] bmax,
51 | float px, float py)
52 | {
53 | // Check for horizontal overlap.
54 | // The segment is shrunken a little so that slabs which touch
55 | // at end points are not connected.
56 | float minx = (float)Math.Max(amin[0]+px,bmin[0]+px);
57 | float maxx = (float)Math.Min(amax[0]-px,bmax[0]-px);
58 | if (minx > maxx)
59 | return false;
60 |
61 | // Check vertical overlap.
62 | float ad = (amax[1]-amin[1]) / (amax[0]-amin[0]);
63 | float ak = amin[1] - ad*amin[0];
64 | float bd = (bmax[1]-bmin[1]) / (bmax[0]-bmin[0]);
65 | float bk = bmin[1] - bd*bmin[0];
66 | float aminy = ad*minx + ak;
67 | float amaxy = ad*maxx + ak;
68 | float bminy = bd*minx + bk;
69 | float bmaxy = bd*maxx + bk;
70 | float dmin = bminy - aminy;
71 | float dmax = bmaxy - amaxy;
72 |
73 | // Crossing segments always overlap.
74 | if (dmin*dmax < 0)
75 | return true;
76 |
77 | // Check for overlap at endpoints.
78 | float thr = dtSqr(py*2);
79 | if (dmin*dmin <= thr || dmax*dmax <= thr)
80 | return true;
81 |
82 | return false;
83 | }
84 |
85 | public static float getSlabCoord(float[] va, int side)
86 | {
87 | if (side == 0 || side == 4)
88 | return va[0];
89 | else if (side == 2 || side == 6)
90 | return va[2];
91 | return 0;
92 | }
93 | public static float getSlabCoord(float[] va, int vaStart, int side)
94 | {
95 | if (side == 0 || side == 4)
96 | return va[vaStart+0];
97 | else if (side == 2 || side == 6)
98 | return va[vaStart+2];
99 | return 0;
100 | }
101 |
102 |
103 | public static void calcSlabEndPoints(float[] va, int vaStart, float[] vb, int vbStart, float[] bmin, float[] bmax, int side)
104 | {
105 | if (side == 0 || side == 4)
106 | {
107 | if (va[vaStart + 2] < vb[vbStart + 2])
108 | {
109 | bmin[0] = va[vaStart + 2];
110 | bmin[1] = va[vaStart + 1];
111 | bmax[0] = vb[vbStart + 2];
112 | bmax[1] = vb[vbStart + 1];
113 | }
114 | else
115 | {
116 | bmin[0] = vb[vbStart + 2];
117 | bmin[1] = vb[vbStart + 1];
118 | bmax[0] = va[vaStart + 2];
119 | bmax[1] = va[vaStart + 1];
120 | }
121 | }
122 | else if (side == 2 || side == 6)
123 | {
124 | if (va[vaStart + 0] < vb[0])
125 | {
126 | bmin[0] = va[vaStart + 0];
127 | bmin[1] = va[vaStart + 1];
128 | bmax[0] = vb[vbStart + 0];
129 | bmax[1] = vb[vbStart + 1];
130 | }
131 | else
132 | {
133 | bmin[0] = vb[vbStart + 0];
134 | bmin[1] = vb[vbStart + 1];
135 | bmax[0] = va[vaStart + 0];
136 | bmax[1] = va[vaStart + 1];
137 | }
138 | }
139 | }
140 |
141 | public static int computeTileHash(int x, int y, int mask)
142 | {
143 | const uint h1 = 0x8da6b343; // Large multiplicative constants;
144 | const uint h2 = 0xd8163841; // here arbitrarily chosen primes
145 | uint n = (uint)(h1 * x + h2 * y);
146 | return (int)(n & mask);
147 | }
148 |
149 | public static uint allocLink(dtMeshTile tile)
150 | {
151 | if (tile.linksFreeList == Detour.DT_NULL_LINK)
152 | return DT_NULL_LINK;
153 | uint link = tile.linksFreeList;
154 | tile.linksFreeList = tile.links[link].next;
155 | return link;
156 | }
157 |
158 | public static void freeLink(dtMeshTile tile, uint link)
159 | {
160 | tile.links[link].next = tile.linksFreeList;
161 | tile.linksFreeList = link;
162 | }
163 | }
164 | }
165 |
166 |
--------------------------------------------------------------------------------
/RecastDetour/Detour/DetourNavMeshQuery.cs:
--------------------------------------------------------------------------------
1 | /// @class dtQueryFilter
2 | ///
3 | /// The Default Implementation
4 | ///
5 | /// At construction: All area costs default to 1.0. All flags are included
6 | /// and none are excluded.
7 | ///
8 | /// If a polygon has both an include and an exclude flag, it will be excluded.
9 | ///
10 | /// The way filtering works, a navigation mesh polygon must have at least one flag
11 | /// set to ever be considered by a query. So a polygon with no flags will never
12 | /// be considered.
13 | ///
14 | /// Setting the include flags to 0 will result in all polygons being excluded.
15 | ///
16 | /// Custom Implementations
17 | ///
18 | /// DT_VIRTUAL_QUERYFILTER must be defined in order to extend this class.
19 | ///
20 | /// Implement a custom query filter by overriding the virtual passFilter()
21 | /// and getCost() functions. If this is done, both functions should be as
22 | /// fast as possible. Use cached local copies of data rather than accessing
23 | /// your own objects where possible.
24 | ///
25 | /// Custom implementations do not need to adhere to the flags or cost logic
26 | /// used by the default implementation.
27 | ///
28 | /// In order for A* searches to work properly, the cost should be proportional to
29 | /// the travel distance. Implementing a cost modifier less than 1.0 is likely
30 | /// to lead to problems during pathfinding.
31 | ///
32 | /// @see dtNavMeshQuery
33 | ///
34 |
35 | #if DT_POLYREF64
36 | using dtPolyRef = System.UInt64;
37 | //using dtTileRef = System.UInt64;
38 | #else
39 | using dtPolyRef = System.UInt32;
40 | //using dtTileRef = System.UInt32;
41 | #endif
42 |
43 | // Define DT_VIRTUAL_QUERYFILTER if you wish to derive a custom filter from dtQueryFilter.
44 | // On certain platforms indirect or virtual function call is expensive. The default
45 | // setting is to use non-virtual functions, the actual implementations of the functions
46 | // are declared as inline for maximum speed.
47 |
48 | //#define DT_VIRTUAL_QUERYFILTER 1
49 |
50 | namespace RecastDetour.Detour
51 | {
52 | public static partial class Detour{
53 |
54 | public const float H_SCALE = 0.999f; // Search heuristic scale.
55 |
56 | /// Defines polygon filtering and traversal costs for navigation mesh query operations.
57 | /// @ingroup detour
58 | public class dtQueryFilter{
59 | public float[] m_areaCost = new float[DT_MAX_AREAS]; //< Cost per area type. (Used by default implementation.)
60 | public ushort m_includeFlags; //< Flags for polygons that can be visited. (Used by default implementation.)
61 | public ushort m_excludeFlags; //< Flags for polygons that should not be visted. (Used by default implementation.)
62 |
63 | public dtQueryFilter()
64 | {
65 | m_includeFlags=0xffff;
66 | m_excludeFlags=0;
67 | for (int i = 0; i < DT_MAX_AREAS; ++i)
68 | m_areaCost[i] = 1.0f;
69 | }
70 |
71 | /// Returns true if the polygon can be visited. (I.e. Is traversable.)
72 | /// @param[in] ref The reference id of the polygon test.
73 | /// @param[in] tile The tile containing the polygon.
74 | /// @param[in] poly The polygon to test.
75 | #if DT_VIRTUAL_QUERYFILTER
76 | bool dtQueryFilter::passFilter(const dtPolyRef /*ref*/,
77 | const dtMeshTile* /*tile*/,
78 | const dtPoly* poly) const
79 | {
80 | return (poly.flags & m_includeFlags) != 0 && (poly.flags & m_excludeFlags) == 0;
81 | }
82 |
83 | float dtQueryFilter::getCost(const float* pa, const float* pb,
84 | const dtPolyRef /*prevRef*/, const dtMeshTile* /*prevTile*/, const dtPoly* /*prevPoly*/,
85 | const dtPolyRef /*curRef*/, const dtMeshTile* /*curTile*/, const dtPoly* curPoly,
86 | const dtPolyRef /*nextRef*/, const dtMeshTile* /*nextTile*/, const dtPoly* /*nextPoly*/) const
87 | {
88 | return dtVdist(pa, pb) * m_areaCost[curPoly.getArea()];
89 | }
90 | #else
91 | public bool passFilter(dtPolyRef polyRef,
92 | dtMeshTile tile,
93 | dtPoly poly)
94 | {
95 | return (poly.flags & m_includeFlags) != 0 && (poly.flags & m_excludeFlags) == 0;
96 | }
97 | #endif
98 |
99 | /// Returns cost to move from the beginning to the end of a line segment
100 | /// that is fully contained within a polygon.
101 | /// @param[in] pa The start position on the edge of the previous and current polygon. [(x, y, z)]
102 | /// @param[in] pb The end position on the edge of the current and next polygon. [(x, y, z)]
103 | /// @param[in] prevRef The reference id of the previous polygon. [opt]
104 | /// @param[in] prevTile The tile containing the previous polygon. [opt]
105 | /// @param[in] prevPoly The previous polygon. [opt]
106 | /// @param[in] curRef The reference id of the current polygon.
107 | /// @param[in] curTile The tile containing the current polygon.
108 | /// @param[in] curPoly The current polygon.
109 | /// @param[in] nextRef The refernece id of the next polygon. [opt]
110 | /// @param[in] nextTile The tile containing the next polygon. [opt]
111 | /// @param[in] nextPoly The next polygon. [opt]
112 | #if DT_VIRTUAL_QUERYFILTER
113 | float dtQueryFilter::getCost(const float* pa, const float* pb,
114 | const dtPolyRef /*prevRef*/, const dtMeshTile* /*prevTile*/, const dtPoly* /*prevPoly*/,
115 | const dtPolyRef /*curRef*/, const dtMeshTile* /*curTile*/, const dtPoly* curPoly,
116 | const dtPolyRef /*nextRef*/, const dtMeshTile* /*nextTile*/, const dtPoly* /*nextPoly*/) const
117 | {
118 | return dtVdist(pa, pb) * m_areaCost[curPoly.getArea()];
119 | }
120 | #else
121 | public float getCost(float[] pa, float[] pb,
122 | dtPolyRef prevRef, dtMeshTile prevTile, dtPoly prevPoly,
123 | dtPolyRef curRef, dtMeshTile curTile, dtPoly curPoly,
124 | dtPolyRef nextRef, dtMeshTile nextTile, dtPoly nextPoly)
125 | {
126 | return dtVdist(pa, pb) * m_areaCost[curPoly.getArea()];
127 | }
128 | #endif
129 |
130 | /// @name Getters and setters for the default implementation data.
131 | ///@{
132 |
133 | /// Returns the traversal cost of the area.
134 | /// @param[in] i The id of the area.
135 | /// @returns The traversal cost of the area.
136 | public float getAreaCost(int i) {
137 | return m_areaCost[i];
138 | }
139 |
140 | /// Sets the traversal cost of the area.
141 | /// @param[in] i The id of the area.
142 | /// @param[in] cost The new cost of traversing the area.
143 | public void setAreaCost(int i, float cost) {
144 | m_areaCost[i] = cost;
145 | }
146 |
147 | /// Returns the include flags for the filter.
148 | /// Any polygons that include one or more of these flags will be
149 | /// included in the operation.
150 | public ushort getIncludeFlags() {
151 | return m_includeFlags;
152 | }
153 |
154 | /// Sets the include flags for the filter.
155 | /// @param[in] flags The new flags.
156 | public void setIncludeFlags(ushort flags) {
157 | m_includeFlags = flags;
158 | }
159 |
160 | /// Returns the exclude flags for the filter.
161 | /// Any polygons that include one ore more of these flags will be
162 | /// excluded from the operation.
163 | public ushort getExcludeFlags() {
164 | return m_excludeFlags;
165 | }
166 |
167 | /// Sets the exclude flags for the filter.
168 | /// @param[in] flags The new flags.
169 | public void setExcludeFlags(ushort flags) {
170 | m_excludeFlags = flags;
171 | }
172 |
173 | ///@}
174 | }
175 | }
176 | }
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
--------------------------------------------------------------------------------
/RecastDetour/Detour/DetourStatus.cs:
--------------------------------------------------------------------------------
1 | using dtStatus = System.UInt32;
2 |
3 | namespace RecastDetour.Detour
4 | {
5 | public static partial class Detour{
6 | // High level status.
7 | public const uint DT_FAILURE = 1u << 31; // Operation failed.
8 | public const uint DT_SUCCESS = 1u << 30; // Operation succeed.
9 | public const uint DT_IN_PROGRESS = 1u << 29; // Operation still in progress.
10 |
11 | // Detail information for status.
12 | public const uint DT_STATUS_DETAIL_MASK = 0x0ffffff;
13 | public const uint DT_WRONG_MAGIC = 1 << 0; // Input data is not recognized.
14 | public const uint DT_WRONG_VERSION = 1 << 1; // Input data is in wrong version.
15 | public const uint DT_OUT_OF_MEMORY = 1 << 2; // Operation ran out of memory.
16 | public const uint DT_INVALID_PARAM = 1 << 3; // An input parameter was invalid.
17 | public const uint DT_BUFFER_TOO_SMALL = 1 << 4; // Result buffer for the query was too small to store all results.
18 | public const uint DT_OUT_OF_NODES = 1 << 5; // Query ran out of nodes during search.
19 | public const uint DT_PARTIAL_RESULT = 1 << 6; // Query did not reach the end location, returning best guess.
20 |
21 |
22 | // Returns true of status is success.
23 | public static bool dtStatusSucceed(dtStatus status)
24 | {
25 | return (status & DT_SUCCESS) != 0;
26 | }
27 |
28 | // Returns true of status is failure.
29 | public static bool dtStatusFailed(dtStatus status)
30 | {
31 | return (status & DT_FAILURE) != 0;
32 | }
33 |
34 | // Returns true of status is in progress.
35 | public static bool dtStatusInProgress(dtStatus status)
36 | {
37 | return (status & DT_IN_PROGRESS) != 0;
38 | }
39 |
40 | // Returns true if specific detail is set.
41 | public static bool dtStatusDetail(dtStatus status, uint detail)
42 | {
43 | return (status & detail) != 0;
44 | }
45 |
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/RecastDetour/Detour/NavMeshCreateParams.cs:
--------------------------------------------------------------------------------
1 | #if DT_POLYREF64
2 | using dtPolyRef = System.UInt64;
3 | #else
4 | #endif
5 |
6 | namespace RecastDetour.Detour
7 | {
8 | /// Represents the source data used to build an navigation mesh tile.
9 | /// @ingroup detour
10 | /**
11 | @struct dtNavMeshCreateParams
12 | @par
13 |
14 | This structure is used to marshal data between the Recast mesh generation pipeline and Detour navigation components.
15 |
16 | See the rcPolyMesh and rcPolyMeshDetail documentation for detailed information related to mesh structure.
17 |
18 | Units are usually in voxels (vx) or world units (wu). The units for voxels, grid size, and cell size
19 | are all based on the values of #cs and #ch.
20 |
21 | The standard navigation mesh build process is to create tile data using dtCreateNavMeshData, then add the tile
22 | to a navigation mesh using either the dtNavMesh single tile init() function or the dtNavMesh::addTile()
23 | function.
24 |
25 | @see dtCreateNavMeshData
26 |
27 | */
28 | public class NavMeshCreateParams {
29 |
30 | /// @name Polygon Mesh Attributes
31 | /// Used to create the base navigation graph.
32 | /// See #rcPolyMesh for details related to these attributes.
33 | /// @{
34 |
35 | public ushort[] verts; //< The polygon mesh vertices. [(x, y, z) * #vertCount] [Unit: vx]
36 | public int vertCount; //< The number vertices in the polygon mesh. [Limit: >= 3]
37 | public ushort[] polys; //< The polygon data. [Size: #polyCount * 2 * #nvp]
38 | public ushort[] polyFlags; //< The user defined flags assigned to each polygon. [Size: #polyCount]
39 | public byte[] polyAreas; //< The user defined area ids assigned to each polygon. [Size: #polyCount]
40 | public int polyCount; //< Number of polygons in the mesh. [Limit: >= 1]
41 | public int nvp; //< Number maximum number of vertices per polygon. [Limit: >= 3]
42 |
43 | /// @}
44 | /// @name Height Detail Attributes (Optional)
45 | /// See #rcPolyMeshDetail for details related to these attributes.
46 | /// @{
47 |
48 | public uint[] detailMeshes; //< The height detail sub-mesh data. [Size: 4 * #polyCount]
49 | public float[] detailVerts; //< The detail mesh vertices. [Size: 3 * #detailVertsCount] [Unit: wu]
50 | public int detailVertsCount; //< The number of vertices in the detail mesh.
51 | public byte[] detailTris; //< The detail mesh triangles. [Size: 4 * #detailTriCount]
52 | public int detailTriCount; //< The number of triangles in the detail mesh.
53 |
54 | /// @}
55 | /// @name Off-Mesh Connections Attributes (Optional)
56 | /// Used to define a custom point-to-point edge within the navigation graph, an
57 | /// off-mesh connection is a user defined traversable connection made up to two vertices,
58 | /// at least one of which resides within a navigation mesh polygon.
59 | /// @{
60 |
61 | /// Off-mesh connection vertices. [(ax, ay, az, bx, by, bz) * #offMeshConCount] [Unit: wu]
62 | public float[] offMeshConVerts;
63 | /// Off-mesh connection radii. [Size: #offMeshConCount] [Unit: wu]
64 | public float[] offMeshConRad;
65 | /// User defined flags assigned to the off-mesh connections. [Size: #offMeshConCount]
66 | public ushort[] offMeshConFlags;
67 | /// User defined area ids assigned to the off-mesh connections. [Size: #offMeshConCount]
68 | public byte[] offMeshConAreas;
69 | /// The permitted travel direction of the off-mesh connections. [Size: #offMeshConCount]
70 | ///
71 | /// 0 = Travel only from endpoint A to endpoint B.
72 | /// #DT_OFFMESH_CON_BIDIR = Bidirectional travel.
73 | public byte[] offMeshConDir;
74 | /// The user defined ids of the off-mesh connection. [Size: #offMeshConCount]
75 | public uint[] offMeshConUserID;
76 | /// The number of off-mesh connections. [Limit: >= 0]
77 | public int offMeshConCount;
78 |
79 | /// @}
80 | /// @name Tile Attributes
81 | /// @note The tile grid/layer data can be left at zero if the destination is a single tile mesh.
82 | /// @{
83 |
84 | public uint userId; //< The user defined id of the tile.
85 | public int tileX; //< The tile's x-grid location within the multi-tile destination mesh. (Along the x-axis.)
86 | public int tileY; //< The tile's y-grid location within the multi-tile desitation mesh. (Along the z-axis.)
87 | public int tileLayer; //< The tile's layer within the layered destination mesh. [Limit: >= 0] (Along the y-axis.)
88 | public float[] bmin = new float[3]; //< The minimum bounds of the tile. [(x, y, z)] [Unit: wu]
89 | public float[] bmax = new float[3]; //< The maximum bounds of the tile. [(x, y, z)] [Unit: wu]
90 |
91 | /// @}
92 | /// @name General Configuration Attributes
93 | /// @{
94 |
95 | public float walkableHeight; //< The agent height. [Unit: wu]
96 | public float walkableRadius; //< The agent radius. [Unit: wu]
97 | public float walkableClimb; //< The agent maximum traversable ledge. (Up/Down) [Unit: wu]
98 | public float cs; //< The xz-plane cell size of the polygon mesh. [Limit: > 0] [Unit: wu]
99 | public float ch; //< The y-axis cell height of the polygon mesh. [Limit: > 0] [Unit: wu]
100 |
101 | /// True if a bounding volume tree should be built for the tile.
102 | /// @note The BVTree is not normally needed for layered navigation meshes.
103 | public bool buildBvTree;
104 |
105 | /// @}
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/RecastDetour/NavMeshAgent.cs:
--------------------------------------------------------------------------------
1 | using RecastDetour.Detour;
2 | using ServerPlugins.Game;
3 | using Utils;
4 | using Utils.Game;
5 |
6 | namespace RecastDetour
7 | {
8 | public class NavMeshAgent
9 | {
10 | public bool HasPath => CurrentPath != null;
11 | public SmoothPath CurrentPath { get; private set; }
12 | public TundraVector3 Destination { get; private set; }
13 |
14 | public TundraVector3 Position { get; set; }
15 | public NavMeshQuery NavMeshQuery { get; set; }
16 | public float Speed { get; set; }
17 | public float StoppingDistance { get; set; }
18 |
19 | private int _currentPathIndex;
20 | private TundraVector3 _currentDestination;
21 |
22 |
23 | public void SetDestination(TundraVector3 destination)
24 | {
25 | CurrentPath = Pathfinder.ComputeSmoothPath(NavMeshQuery, Position, destination);
26 | if (CurrentPath.Points.Count > 0)
27 | {
28 | _currentPathIndex = 0;
29 | _currentDestination = CurrentPath.Points[0];
30 | Destination = CurrentPath.Points[CurrentPath.PointsCount-1];
31 | }
32 | else
33 | {
34 | CurrentPath = null;
35 | }
36 | }
37 |
38 | public void Integrate(float deltaTime)
39 | {
40 | var maxDistance = Speed * deltaTime;
41 | if (TundraVector3.Distance(Position, _currentDestination) <= StoppingDistance)
42 | {
43 | if (_currentPathIndex < CurrentPath.PointsCount - 1)
44 | {
45 | _currentDestination = CurrentPath.Points[++_currentPathIndex];
46 | Position = TundraVector3.MoveTowards(Position, _currentDestination, maxDistance);
47 | }
48 | else
49 | {
50 | CurrentPath = null;
51 | }
52 | }
53 | else
54 | {
55 | Position = TundraVector3.MoveTowards(Position, _currentDestination, maxDistance);
56 | }
57 | }
58 | }
59 | }
--------------------------------------------------------------------------------
/RecastDetour/NavMeshSerializer.cs:
--------------------------------------------------------------------------------
1 | using System.IO;
2 | using Newtonsoft.Json;
3 | using RecastDetour.Detour;
4 | using dtStatus = System.UInt32;
5 |
6 | namespace RecastDetour
7 | {
8 | public static class NavMeshSerializer
9 | {
10 | public static void Serialize(string path, NavMeshCreateParams mesh)
11 | {
12 | File.WriteAllText(path, JsonConvert.SerializeObject(mesh));
13 | }
14 |
15 | public static NavMeshCreateParams Deserialize(string path)
16 | {
17 | return JsonConvert.DeserializeObject(File.ReadAllText(path));
18 | }
19 |
20 | public static NavMeshQuery CreateMeshQuery(NavMeshCreateParams meshCreateParams)
21 | {
22 | Detour.Detour.dtRawTileData navData;
23 | if (!Detour.Detour.dtCreateNavMeshData(meshCreateParams, out navData))
24 | {
25 | return null;
26 | }
27 |
28 | var m_navMesh = new NavMesh();
29 | dtStatus status;
30 |
31 | status = m_navMesh.init(navData, (int)Detour.Detour.dtTileFlags.DT_TILE_FREE_DATA);
32 | if (Detour.Detour.dtStatusFailed(status))
33 | {
34 | return null;
35 | }
36 |
37 | var m_navQuery = new NavMeshQuery();
38 | status = m_navQuery.init(m_navMesh, 2048);
39 | if (Detour.Detour.dtStatusFailed(status))
40 | {
41 | return null;
42 | }
43 |
44 | return m_navQuery;
45 | }
46 | }
47 | }
--------------------------------------------------------------------------------
/RecastDetour/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("RecastDetour")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("RecastDetour")]
13 | [assembly: AssemblyCopyright("Copyright © 2018")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("6c4bedd5-f000-4994-b000-2f5f310f6e3a")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/RecastDetour/Recast/BuildContext.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using System.Text;
5 |
6 | //Example implementation of rcContext
7 | namespace RecastDetour.Recast
8 | {
9 | public partial class Recast{
10 |
11 | /// Recast build context.
12 | public class BuildContext : rcContext
13 | {
14 | private Stopwatch[] m_Stopwatches = new Stopwatch[(int)rcTimerLabel.RC_MAX_TIMERS];
15 |
16 | public bool m_Dirty = false;
17 |
18 | private class LogMessage{
19 | public rcLogCategory m_Category;
20 | public string m_Message;
21 |
22 | public LogMessage(rcLogCategory category, string msg){
23 | m_Category = category;
24 | m_Message = msg;
25 | }
26 | }
27 |
28 | const int MAX_MESSAGES = 1000;
29 | List m_Messages = new List();
30 |
31 | public BuildContext()
32 | {
33 | for (int i = 0; i < (int)rcTimerLabel.RC_MAX_TIMERS; ++i) {
34 | m_Stopwatches[i] = new Stopwatch();
35 | }
36 | resetTimers();
37 | }
38 |
39 |
40 | protected override void doResetLog()
41 | {
42 | m_Messages.Clear();
43 | }
44 |
45 | protected override void doLog(rcLogCategory category, string msg)
46 | {
47 | m_Messages.Add(new LogMessage(category, msg));
48 | if (m_Messages.Count > MAX_MESSAGES){
49 | m_Messages.RemoveAt(0);
50 | }
51 |
52 | m_Dirty = true;
53 | }
54 |
55 | protected override void doResetTimers()
56 | {
57 | for (int i = 0; i < (int)rcTimerLabel.RC_MAX_TIMERS; ++i)
58 | m_Stopwatches[i].Reset();
59 | }
60 |
61 | protected override void doStartTimer(rcTimerLabel label)
62 | {
63 | m_Stopwatches[(int)label].Start();
64 | }
65 |
66 | protected override void doStopTimer(rcTimerLabel label)
67 | {
68 | m_Stopwatches[(int)label].Stop();
69 | }
70 |
71 | protected override long doGetAccumulatedTime(rcTimerLabel label)
72 | {
73 | return m_Stopwatches[(int)label].ElapsedMilliseconds;
74 | }
75 |
76 | protected override double doGetAccumulatedTimeHiResolution(rcTimerLabel label) {
77 |
78 | if (!Stopwatch.IsHighResolution) {
79 | return -1.0;
80 | }
81 |
82 | if (m_Stopwatches[(int)label].IsRunning) {
83 | Console.WriteLine("Stopwatch " + label.ToString() + " was not stopped prior to output");
84 | }
85 |
86 | double seconds = (double)m_Stopwatches[(int)label].ElapsedTicks / (double)Stopwatch.Frequency;
87 |
88 | return seconds * 1000.0;
89 | }
90 |
91 |
92 | private void logLine(rcTimerLabel label, string name, double pc, int level = 0)
93 | {
94 | double t = getAccumulatedTimeHiResolution(label);
95 | if (t <= 0.0f)
96 | return;
97 | string raster = "";
98 |
99 | if (level > 0) {
100 | raster += new string(' ', 4*level);
101 | }
102 | raster += name + ": ";
103 | if (raster.Length < 25) {
104 | raster += new string(' ', 25 - raster.Length);
105 | }
106 |
107 | int secondColumn = 40;
108 | if (level != 0) {
109 | raster += "";
110 | secondColumn += 12;
111 | }
112 | raster += string.Format("{0:N2}", t) + "ms ";
113 | if (raster.Length < secondColumn) {
114 | raster += new string(' ', secondColumn - raster.Length);
115 | }
116 | raster += "(" + string.Format("{0:N1}", t * pc) + "%)";
117 | if (level != 0) {
118 | raster += "";
119 | }
120 | log(rcLogCategory.RC_LOG_PROGRESS, raster);
121 |
122 | m_PercentCheck += t * pc;
123 | m_SumCheck += t;
124 | }
125 |
126 | private double m_PercentCheck = 0.0;
127 | private double m_SumCheck = 0.0;
128 | public void logBuildTimes()
129 | {
130 | double totalTime = getAccumulatedTimeHiResolution(rcTimerLabel.RC_TIMER_TOTAL);
131 | double pc = 100.0 / totalTime;
132 |
133 | m_PercentCheck = 0.0;
134 | m_SumCheck = 0.0;
135 |
136 | log(rcLogCategory.RC_LOG_PROGRESS, "Build Times");
137 | logLine(rcTimerLabel.RC_TIMER_RASTERIZE_TRIANGLES, "- Rasterize", pc);
138 | logLine(rcTimerLabel.RC_TIMER_BUILD_COMPACTHEIGHTFIELD, "- Build Compact", pc);
139 | logLine(rcTimerLabel.RC_TIMER_FILTER_BORDER, "- Filter Border", pc);
140 | logLine(rcTimerLabel.RC_TIMER_FILTER_WALKABLE, "- Filter Walkable", pc);
141 | logLine(rcTimerLabel.RC_TIMER_ERODE_AREA, "- Erode Area", pc);
142 | logLine(rcTimerLabel.RC_TIMER_MEDIAN_AREA, "- Median Area", pc);
143 | logLine(rcTimerLabel.RC_TIMER_MARK_BOX_AREA, "- Mark Box Area", pc);
144 | logLine(rcTimerLabel.RC_TIMER_MARK_CONVEXPOLY_AREA, "- Mark Convex Area", pc);
145 | logLine(rcTimerLabel.RC_TIMER_MARK_CYLINDER_AREA, "- Mark Cylinder Area", pc);
146 | logLine(rcTimerLabel.RC_TIMER_BUILD_DISTANCEFIELD, "- Build Distance Field", pc);
147 | logLine(rcTimerLabel.RC_TIMER_BUILD_DISTANCEFIELD_DIST, "- Distance", pc, 1);
148 | logLine(rcTimerLabel.RC_TIMER_BUILD_DISTANCEFIELD_BLUR, "- Blur", pc, 1);
149 | logLine(rcTimerLabel.RC_TIMER_BUILD_REGIONS, "- Build Regions", pc);
150 | logLine(rcTimerLabel.RC_TIMER_BUILD_REGIONS_WATERSHED, "- Watershed", pc, 1);
151 | logLine(rcTimerLabel.RC_TIMER_BUILD_REGIONS_EXPAND, "- Expand", pc, 2);
152 | logLine(rcTimerLabel.RC_TIMER_BUILD_REGIONS_FLOOD, "- Find Basins", pc, 2);
153 | logLine(rcTimerLabel.RC_TIMER_BUILD_REGIONS_FILTER, "- Filter", pc, 1);
154 | logLine(rcTimerLabel.RC_TIMER_BUILD_LAYERS, "- Build Layers", pc);
155 | logLine(rcTimerLabel.RC_TIMER_BUILD_CONTOURS, "- Build Contours", pc);
156 | logLine(rcTimerLabel.RC_TIMER_BUILD_CONTOURS_TRACE, "- Trace", pc, 1);
157 | logLine(rcTimerLabel.RC_TIMER_BUILD_CONTOURS_SIMPLIFY, "- Simplify", pc, 1);
158 | logLine(rcTimerLabel.RC_TIMER_BUILD_POLYMESH, "- Build Polymesh", pc);
159 | logLine(rcTimerLabel.RC_TIMER_BUILD_POLYMESHDETAIL, "- Build Polymesh Detail", pc);
160 | logLine(rcTimerLabel.RC_TIMER_MERGE_POLYMESH, "- Merge Polymeshes", pc);
161 | logLine(rcTimerLabel.RC_TIMER_MERGE_POLYMESHDETAIL, "- Merge Polymesh Details", pc);
162 | log(rcLogCategory.RC_LOG_PROGRESS, "=== TOTAL: " + totalTime + " ms ===");
163 | }
164 |
165 | public string dumpLog()
166 | {
167 | StringBuilder sb = new StringBuilder();
168 |
169 | foreach(LogMessage msg in m_Messages){
170 | sb.AppendLine(msg.m_Category.ToString() + ": " + msg.m_Message);
171 | }
172 | return sb.ToString();
173 | }
174 |
175 | public int getLogCount()
176 | {
177 | return m_Messages.Count;
178 | }
179 | };
180 | }
181 | }
--------------------------------------------------------------------------------
/RecastDetour/RecastDetour.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {6C4BEDD5-F000-4994-B000-2F5F310F6E3A}
8 | Library
9 | Properties
10 | RecastDetour
11 | RecastDetour
12 | v3.5
13 | 512
14 |
15 |
16 |
17 | true
18 | full
19 | false
20 | bin\Debug\
21 | DEBUG;TRACE
22 | prompt
23 | 4
24 |
25 |
26 | pdbonly
27 | true
28 | bin\Release\
29 | TRACE
30 | prompt
31 | 4
32 |
33 |
34 |
35 | ..\packages\MathFloat.1.0.1.0\lib\net20\MathFloat.dll
36 |
37 |
38 | ..\packages\Newtonsoft.Json.11.0.2\lib\net35\Newtonsoft.Json.dll
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 | {73957A5C-7298-4BD7-97A7-6E572B50D155}
78 | Utils
79 |
80 |
81 |
82 |
--------------------------------------------------------------------------------
/RecastDetour/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/ServerPlugins/Authentication/EncryptionData.cs:
--------------------------------------------------------------------------------
1 | namespace ServerPlugins.Authentication
2 | {
3 | internal class EncryptionData
4 | {
5 | public string AesKey;
6 | public byte[] AesKeyEncrypted;
7 | }
8 | }
--------------------------------------------------------------------------------
/ServerPlugins/Database/PasswordResetData.cs:
--------------------------------------------------------------------------------
1 | namespace ServerPlugins.Database
2 | {
3 | public class PasswordResetData
4 | {
5 | public string Email { get; set; }
6 | public string Code { get; set; }
7 | }
8 | }
--------------------------------------------------------------------------------
/ServerPlugins/Database/SqlAccountData.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | namespace ServerPlugins.Database
5 | {
6 | public class SqlAccountData
7 | {
8 | public int AccountId { get; set; }
9 | public string Email { get; set; }
10 | public string Password { get; set; }
11 | public string Token { get; set; }
12 | public bool IsAdmin { get; set; }
13 | public bool IsGuest { get; set; }
14 | public bool IsEmailConfirmed { get; set; }
15 |
16 | public Dictionary Properties { get; set; }
17 |
18 | public event Action OnChange;
19 |
20 | public void MarkAsDirty()
21 | {
22 | OnChange?.Invoke(this);
23 | }
24 | }
25 | }
--------------------------------------------------------------------------------
/ServerPlugins/Game/Components/BuffComponent.cs:
--------------------------------------------------------------------------------
1 | namespace ServerPlugins.Game.Components
2 | {
3 | public class BuffComponent : Component
4 | {
5 | public override void Update(float delta)
6 | {
7 | //check if any buffs have expired
8 | }
9 | }
10 | }
--------------------------------------------------------------------------------
/ServerPlugins/Game/Components/Component.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using DarkRift;
4 | using DarkRift.Server;
5 | using ServerPlugins.Game.Entities;
6 | using Utils.Game;
7 |
8 | namespace ServerPlugins.Game.Components
9 | {
10 | public abstract class Component
11 | {
12 | public Entity Entity;
13 |
14 | public virtual void Start() { }
15 | public virtual void Update(float delta) { }
16 | public virtual void Destroy() { }
17 | }
18 | }
--------------------------------------------------------------------------------
/ServerPlugins/Game/Components/NavigationComponent.cs:
--------------------------------------------------------------------------------
1 | using DarkRift;
2 | using RecastDetour;
3 | using RecastDetour.Detour;
4 | using Utils;
5 | using Utils.Game;
6 | using Utils.Packets;
7 |
8 | namespace ServerPlugins.Game.Components
9 | {
10 | public class NavigationComponent : Component
11 | {
12 | private readonly NavMeshAgent _agent = new NavMeshAgent();
13 | TundraVector3 lastDestination;
14 |
15 | public NavMeshQuery NavMeshQuery
16 | {
17 | get => _agent.NavMeshQuery;
18 | set => _agent.NavMeshQuery = value;
19 | }
20 |
21 | public float Speed
22 | {
23 | get => _agent.Speed;
24 | set => _agent.Speed = value;
25 | }
26 |
27 | public bool HasPath => _agent.HasPath;
28 |
29 | public void Warp(TundraVector3 position)
30 | {
31 | _agent.Position = position;
32 | }
33 |
34 | public void SetDestination(TundraVector3 destination)
35 | {
36 | _agent.SetDestination(destination);
37 | }
38 |
39 | public override void Update(float deltaT)
40 | {
41 | if (_agent.Destination != lastDestination)
42 | {
43 | var packet = new AckNavigateToPacket
44 | {
45 | EntityID = Entity.ID,
46 | Path = _agent.CurrentPath,
47 | Speed = _agent.Speed,
48 | StoppingDistance = _agent.StoppingDistance
49 | };
50 |
51 | foreach (var observer in Entity.Observers)
52 | {
53 | observer.Client.SendMessage(Message.Create(MessageTags.NavigateTo, packet), SendMode.Unreliable);
54 | }
55 |
56 | lastDestination = _agent.Destination;
57 |
58 | Entity.Game.Log("Published: " + packet, LogType.Info);
59 | }
60 |
61 | if (_agent.CurrentPath != null)
62 | {
63 | _agent.Integrate(deltaT);
64 | }
65 | }
66 |
67 | public void Reset()
68 | {
69 | }
70 | }
71 | }
--------------------------------------------------------------------------------
/ServerPlugins/Game/Components/SpawnComponent.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 | using DarkRift;
4 | using Utils;
5 | using Utils.Packets;
6 |
7 | namespace ServerPlugins.Game.Components
8 | {
9 | public class SpawnComponent : Component
10 | {
11 | public override void Start()
12 | {
13 | //Warp agent to initial position
14 | Entity.GetComponent().Warp(Entity.Position);
15 | }
16 |
17 | private readonly HashSet _currentObservers = new HashSet();
18 | public override void Update(float delta)
19 | {
20 | //Send Spawn-notification when an observer was added
21 | foreach (var observer in Entity.Observers.Where(player => !_currentObservers.Contains(player.ID)))
22 | {
23 | //TODO: Include pending navigation if Entity.NavMeshComponent hasPath
24 | observer.Client.SendMessage(Message.Create(MessageTags.SpawnEntity,
25 | new EntityPacket
26 | {
27 | NetworkEntity = Entity,
28 | //if the observer is the player himself, he has authority,
29 | //check this field on client-side to either spawn player-prefab or networkview-prefab
30 | HasAuthority = observer.ID == Entity.ID
31 | }), SendMode.Reliable);
32 |
33 | _currentObservers.Add(observer.ID);
34 |
35 | }
36 | }
37 | }
38 | }
--------------------------------------------------------------------------------
/ServerPlugins/Game/Entities/Entity.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 | using DarkRift;
4 | using ServerPlugins.Game.Components;
5 | using Utils;
6 | using Utils.Packets;
7 |
8 | namespace ServerPlugins.Game.Entities
9 | {
10 | public class Entity : NetworkEntity
11 | {
12 | private EntityState tmpState;
13 | private readonly List _components = new List();
14 |
15 | private Entity Target;
16 | public GamePlugin Game;
17 | public NavigationComponent navComponent;
18 | public readonly List Observers = new List();
19 |
20 | public void SetTarget(Entity target)
21 | {
22 | Target = target;
23 | TargetID = target?.ID ?? 0; //for network sync.
24 | }
25 |
26 | public T AddComponent() where T: Component, new()
27 | {
28 | var component = new T { Entity = this };
29 | _components.Add(component);
30 | return component;
31 | }
32 |
33 | public T GetComponent() where T : Component
34 | {
35 | return (T)_components.FirstOrDefault(component => component is T);
36 | }
37 |
38 | public virtual void Start()
39 | {
40 | navComponent = GetComponent();
41 |
42 | foreach (var component in _components)
43 | {
44 | component.Start();
45 | }
46 | }
47 | public virtual void Update(float delta)
48 | {
49 | //TODO: area of interest
50 | //if (Target != null && !Target.Visible)
51 | // SetTarget(null);
52 |
53 | tmpState = State;
54 | foreach (var component in _components)
55 | {
56 | component.Update(delta);
57 | }
58 | }
59 |
60 | public void LateUpdate()
61 | {
62 | //Send update with state has changed in Update
63 | if (tmpState != State)
64 | {
65 | foreach (var observer in Observers)
66 | {
67 | observer.Client.SendMessage(Message.Create(MessageTags.ChangeState, new ChangStatePacket {EntityID = ID, State = State}),
68 | SendMode.Reliable);
69 | }
70 | }
71 | }
72 |
73 | public virtual void Destroy()
74 | {
75 | foreach (var component in _components)
76 | {
77 | component.Destroy();
78 | }
79 | }
80 |
81 | //public bool IsMoving()
82 | //{
83 | // // -> agent.hasPath will be true if stopping distance > 0, so we can't
84 | // // really rely on that.
85 | // // -> IsDirty is true while calculating the path, which is good
86 | // // -> remainingDistance is the distance to the last path point, so it
87 | // // also works when clicking somewhere onto a obstacle that isn'
88 | // // directly reachable.
89 | // return agent.IsDirty ||
90 | // agent.RemainingDistance > agent.StoppingDistance ||
91 | // agent.Velocity != Vector3.Zero;
92 | //}
93 |
94 | public override string ToString()
95 | {
96 | return Name + "(ID: " + ID + ")";
97 | }
98 | }
99 | }
--------------------------------------------------------------------------------
/ServerPlugins/Game/Entities/Monster.cs:
--------------------------------------------------------------------------------
1 | namespace ServerPlugins.Game.Entities
2 | {
3 | public class Monster : Entity
4 | {
5 |
6 | }
7 | }
--------------------------------------------------------------------------------
/ServerPlugins/Game/Entities/Player.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using DarkRift;
4 | using DarkRift.Server;
5 | using Utils;
6 | using Utils.Game;
7 | using Utils.Packets;
8 |
9 | namespace ServerPlugins.Game.Entities
10 | {
11 | public class Player : Entity
12 | {
13 | public readonly IClient Client;
14 |
15 | readonly Dictionary _messages = new Dictionary();
16 | readonly Dictionary> _handlers = new Dictionary>();
17 |
18 | public Player(IClient client)
19 | {
20 | Client = client;
21 | Client.MessageReceived += OnMessageFromPlayer;
22 | }
23 |
24 | private void OnMessageFromPlayer(object sender, MessageReceivedEventArgs e)
25 | {
26 | var msg = e.GetMessage();
27 | if (msg != null && _handlers.ContainsKey(msg.Tag))
28 | {
29 | lock (_messages)
30 | {
31 | //Overwrite existing message of the same tag
32 | _messages[msg.Tag] = msg;
33 | }
34 | }
35 | }
36 |
37 | public override void Start()
38 | {
39 | base.Start();
40 | _handlers.Add(MessageTags.NavigateTo, HandleNavigateTo);
41 | }
42 |
43 | private void HandleNavigateTo(Message message)
44 | {
45 | var data = message.Deserialize();
46 | if (data != null)
47 | {
48 | navComponent.SetDestination(TundraVector3.Create(data.Destination.X, data.Destination.Y, data.Destination.Z));
49 | }
50 | }
51 |
52 | public override void Update(float delta)
53 | {
54 | base.Update(delta);
55 | lock (_messages)
56 | {
57 | foreach (var tag in _messages.Keys)
58 | {
59 | _handlers[tag].Invoke(_messages[tag]);
60 | }
61 | _messages.Clear();
62 | }
63 |
64 | switch (State)
65 | {
66 | case EntityState.Idle:
67 | UpdateIdle();
68 | break;
69 | case EntityState.Moving:
70 | UpdateMoving();
71 | break;
72 | case EntityState.Casting:
73 | UpdateCasting();
74 | break;
75 | case EntityState.Dead:
76 | UpdateDead();
77 | break;
78 | default:
79 | Game.Log("Entity " + ID + " in unknown state", LogType.Warning);
80 | break;
81 |
82 | }
83 | }
84 |
85 |
86 |
87 | private void UpdateIdle()
88 | {
89 | if (Health == 0)
90 | {
91 | Die();
92 | State = EntityState.Dead;
93 | }
94 | else if (navComponent.HasPath)
95 | {
96 | State = EntityState.Moving;
97 | }
98 | }
99 |
100 | private void UpdateMoving()
101 | {
102 | if (Health == 0)
103 | {
104 | Die();
105 | State = EntityState.Dead;
106 | }
107 | else if (navComponent.HasPath)
108 | {
109 | State = EntityState.Moving;
110 | }
111 | else
112 | {
113 | State = EntityState.Idle;
114 | }
115 | }
116 | private void UpdateCasting()
117 | {
118 |
119 | }
120 |
121 | private void UpdateDead()
122 | {
123 |
124 | }
125 |
126 | void Die()
127 | {
128 | navComponent.Reset();
129 | SetTarget(null);
130 | }
131 | }
132 | }
--------------------------------------------------------------------------------
/ServerPlugins/Game/GamePlugin.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using System.Collections.Generic;
4 | using System.Collections.Concurrent;
5 | using System.Diagnostics;
6 | using System.Threading;
7 | using DarkRift;
8 | using DarkRift.Server;
9 | using RecastDetour;
10 | using RecastDetour.Detour;
11 | using ServerPlugins.Game.Components;
12 | using ServerPlugins.Game.Entities;
13 | using Utils.Game;
14 |
15 | namespace ServerPlugins.Game
16 | {
17 | ///
18 | /// This Plugin goes to the spawned server
19 | ///
20 | public class GamePlugin : ServerPluginBase
21 | {
22 | public readonly int Tickrate;
23 |
24 | //Reserve EntityID 0 for null, (example: no target selected)
25 | private uint _nextEntityID = 1;
26 |
27 | public readonly Dictionary Entities;
28 | private readonly ConcurrentQueue _spawnQueue;
29 | private readonly ConcurrentQueue _despawnQueue;
30 |
31 | public override bool ThreadSafe => false;
32 | public bool Running { get; set; }
33 |
34 | public event Action Started;
35 |
36 | private long tick, tock;
37 | private long _frameCounter = 0;
38 | public NavMeshQuery NavMeshQuery;
39 |
40 |
41 | public GamePlugin(PluginLoadData pluginLoadData) : base(pluginLoadData)
42 | {
43 | Tickrate = Convert.ToInt32(pluginLoadData.Settings.Get(nameof(Tickrate)));
44 |
45 | Entities = new Dictionary();
46 | _spawnQueue = new ConcurrentQueue();
47 | _despawnQueue = new ConcurrentQueue();
48 | }
49 |
50 | public void LoadLevel(string levelName)
51 | {
52 | NavMeshQuery = NavMeshSerializer.CreateMeshQuery(NavMeshSerializer.Deserialize("Levels/" + levelName + ".nav"));
53 | //The YOffset requires the world to have a valid NavMesh-Position at (0,0,0)
54 | Pathfinder.YOffset = Pathfinder.GetClosestPointOnNavMesh(NavMeshQuery, TundraVector3.Create(0f, 0f, 0f)).Y;
55 | AddEntity(new Monster {Name = "Monster", Position = TundraVector3.Zero});
56 | }
57 |
58 | public void AddEntity(Entity entity)
59 | {
60 | entity.ID = _nextEntityID++;
61 | entity.Game = this;
62 | entity.Position = TundraVector3.Zero;
63 | entity.AddComponent();
64 | var navComponent = entity.AddComponent();
65 | navComponent.NavMeshQuery = NavMeshQuery;
66 | navComponent.Speed = 3f;
67 | _spawnQueue.Enqueue(entity);
68 | }
69 |
70 | public void RemoveEntity(Entity entity)
71 | {
72 | _despawnQueue.Enqueue(entity);
73 | }
74 |
75 | public void Start()
76 | {
77 | Running = true;
78 |
79 | Started?.Invoke();
80 |
81 | float updateTime = 1000 / (float)Tickrate;
82 | long lastTime = DateTime.Now.Ticks;
83 |
84 | while (Running)
85 | {
86 | long now = DateTime.Now.Ticks;
87 | var delta = (float)TimeSpan.FromTicks(now - lastTime).TotalSeconds;
88 | lastTime = now;
89 |
90 | while (_spawnQueue.Count > 0 && _spawnQueue.TryDequeue(out var entity))
91 | {
92 | //TODO: replace foreach-over-all-entites with foreach-entity-in-AREA-OF-INTERESET
93 |
94 | //let all players observe this unit
95 | foreach (Player player in Entities.Values.Where(e => e is Player))
96 | {
97 | WriteEvent("Adding " + player.ID + " as observer to " + entity.ID, LogType.Info);
98 | entity.Observers.Add(player);
99 | }
100 |
101 | Entities.Add(entity.ID, entity);
102 | if (entity is Player newPlayer)
103 | {
104 | //register the player to all units (around him, including himself), so they send him notifications when something updates
105 | foreach (var unit in Entities.Values)
106 | {
107 | WriteEvent("Adding new Player " + newPlayer.ID + " as observer to " + unit.ID, LogType.Info);
108 | unit.Observers.Add(newPlayer);
109 | }
110 | }
111 |
112 | entity.Start();
113 | }
114 |
115 | while (_despawnQueue.Count > 0 && _despawnQueue.TryDequeue(out var entity))
116 | {
117 | Entities.Remove(entity.ID);
118 | entity.Destroy();
119 | }
120 |
121 | foreach (var entity in Entities.Values)
122 | {
123 | entity.Update(delta);
124 |
125 | }
126 |
127 | foreach (var entity in Entities.Values)
128 | {
129 | entity.LateUpdate();
130 | }
131 |
132 | var elapsed = (float) TimeSpan.FromTicks(DateTime.Now.Ticks - now).TotalMilliseconds;
133 | if (elapsed < updateTime)
134 | Thread.Sleep((int) (updateTime - elapsed));
135 | }
136 | }
137 |
138 | public void Stop()
139 | {
140 | Running = false;
141 | }
142 |
143 | public void Log(string message, LogType logType)
144 | {
145 | WriteEvent(message, logType);
146 | }
147 | }
148 | }
--------------------------------------------------------------------------------
/ServerPlugins/Game/Levels/Act1.nav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/proepkes/MSF-DarkRiftServer/9ba50c4bf2ae11a6a9b46ea7d438f927852625be/ServerPlugins/Game/Levels/Act1.nav
--------------------------------------------------------------------------------
/ServerPlugins/Mail/MailPlugin.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Net;
3 | using System.Net.Mail;
4 | using DarkRift;
5 | using DarkRift.Server;
6 |
7 | namespace ServerPlugins.Mail
8 | {
9 | public class MailPlugin : ServerPluginBase
10 | {
11 | private SmtpClient SmtpClient;
12 |
13 | public string SmtpPassword { get; set; }
14 |
15 | public string SmtpUsername { get; set; }
16 |
17 | public int SmtpPort { get; set; }
18 |
19 | public string SmtpHost { get; set; }
20 | public string SenderDisplayName { get; set; }
21 |
22 | public string EmailFrom { get; set; }
23 |
24 | public MailPlugin(PluginLoadData pluginLoadData) : base(pluginLoadData)
25 | {
26 | SmtpHost = pluginLoadData.Settings.Get(nameof(SmtpHost));
27 | SmtpPort = Convert.ToInt32(pluginLoadData.Settings.Get(nameof(SmtpPort)));
28 | SmtpUsername = pluginLoadData.Settings.Get(nameof(SmtpUsername));
29 | SmtpPassword = pluginLoadData.Settings.Get(nameof(SmtpPassword));
30 | SenderDisplayName = pluginLoadData.Settings.Get(nameof(SenderDisplayName));
31 | EmailFrom = pluginLoadData.Settings.Get(nameof(EmailFrom));
32 | }
33 |
34 | protected override void Loaded(LoadedEventArgs args)
35 | {
36 | base.Loaded(args);
37 |
38 | SetupSmtpClient();
39 | }
40 |
41 | protected virtual void SetupSmtpClient()
42 | {
43 | // Configure mail client
44 | SmtpClient = new SmtpClient(SmtpHost, SmtpPort)
45 | {
46 | Credentials = new NetworkCredential(SmtpUsername, SmtpPassword),
47 | EnableSsl = true
48 | };
49 |
50 | // set the network credentials
51 |
52 | SmtpClient.SendCompleted += (sender, args) =>
53 | {
54 | if (args.Error != null) WriteEvent("EMail send error:" + args.Error, LogType.Fatal);
55 | };
56 |
57 | ServicePointManager.ServerCertificateValidationCallback =
58 | delegate { return true; };
59 | }
60 |
61 | public void SendMail(string to, string subject, string body)
62 | {
63 | // Create the mail message (from, to, subject, body)
64 | var mailMessage = new MailMessage();
65 | mailMessage.From = new MailAddress(EmailFrom, SenderDisplayName);
66 | mailMessage.To.Add(to);
67 |
68 | mailMessage.Subject = subject;
69 | mailMessage.Body = body;
70 | mailMessage.IsBodyHtml = true;
71 | mailMessage.Priority = MailPriority.High;
72 |
73 |
74 | // send the mail
75 | SmtpClient.SendAsync(mailMessage, "");
76 | }
77 | }
78 | }
--------------------------------------------------------------------------------
/ServerPlugins/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("Plugins")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("Plugins")]
13 | [assembly: AssemblyCopyright("Copyright © 2018")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("3f3234ee-ed0e-44e3-8024-05cc293f568e")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/ServerPlugins/RoomHandler/RegisteredRoom.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using DarkRift;
5 | using DarkRift.Server;
6 | using Utils;
7 | using Utils.Messages.Responses;
8 | using Utils.Packets;
9 |
10 | namespace ServerPlugins.RoomHandler
11 | {
12 | ///
13 | /// This is an instance of the room in master server
14 | ///
15 | public class RegisteredRoom
16 | {
17 | private class ClientEquality : IEqualityComparer
18 | {
19 | public bool Equals(IClient x, IClient y)
20 | {
21 | return x.ID == y.ID;
22 | }
23 |
24 | public int GetHashCode(IClient obj)
25 | {
26 | return obj.ID;
27 | }
28 | }
29 |
30 | public delegate void GetAccessCallback(RoomAccessPacket access, string error);
31 |
32 | private readonly Dictionary _accessesInUse;
33 | private readonly Dictionary _pendingRequests;
34 |
35 | private readonly Dictionary _players;
36 | private readonly Dictionary _unconfirmedAccesses;
37 |
38 | public int ID { get; }
39 | public IClient Client { get; }
40 | public RoomOptions Options { get; private set; }
41 |
42 | public int OnlineCount => _accessesInUse.Count;
43 |
44 |
45 | public RegisteredRoom(int id, IClient client, RoomOptions options)
46 | {
47 | ID = id;
48 | Client = client;
49 | Options = options;
50 |
51 | _unconfirmedAccesses = new Dictionary();
52 | _players = new Dictionary();
53 | _accessesInUse = new Dictionary();
54 | _pendingRequests = new Dictionary(new ClientEquality());
55 |
56 | //Connection from masterserver to room
57 | Client.MessageReceived += OnMessageReceived;
58 | }
59 |
60 | private void OnMessageReceived(object sender, MessageReceivedEventArgs e)
61 | {
62 | var message = e.GetMessage();
63 | if (message != null)
64 | {
65 | switch (message.Tag)
66 | {
67 | case MessageTags.ProvideRoomAccessCheckSuccess:
68 | HandleProvideRoomAccessCheckSuccess(message);
69 | break;
70 | }
71 | }
72 | }
73 |
74 | private void HandleProvideRoomAccessCheckSuccess(Message message)
75 | {
76 | var data = message.Deserialize();
77 | if (data != null)
78 | {
79 | var client = _pendingRequests.Keys.FirstOrDefault(key => key.ID == data.ClientID);
80 | if (client != null)
81 | {
82 | //call the callback
83 | _pendingRequests[client](data, null);
84 |
85 | var access = new RoomAccessData
86 | {
87 | Access = data,
88 | Client = client,
89 | Timeout = DateTime.Now.AddSeconds(20)
90 | };
91 | _unconfirmedAccesses[data.Token] = access;
92 | _pendingRequests.Remove(client);
93 | }
94 | }
95 | }
96 |
97 | ///
98 | /// Sends a request to room, to retrieve an access to it for a specified peer,
99 | /// with some extra properties
100 | ///
101 | public void GetAccess(IClient client, GetAccessCallback callback)
102 | {
103 | // If request is already pending
104 | if (_pendingRequests.ContainsKey(client))
105 | {
106 | callback.Invoke(null, "You've already requested an access to this room");
107 | return;
108 | }
109 |
110 | // If player is already in the game
111 | if (_players.ContainsKey(client.ID))
112 | {
113 | callback.Invoke(null, "You are already in this room");
114 | return;
115 | }
116 |
117 | // If player has already received an access and didn't claim it
118 | // but is requesting again - send him the old one
119 | var currentAccess = _unconfirmedAccesses.Values.FirstOrDefault(v => v.Client.ID == client.ID);
120 | if (currentAccess != null)
121 | {
122 | // Restore the timeout //TODO: Timeout-Setting (no fixed value of 20)
123 | currentAccess.Timeout = DateTime.Now.AddSeconds(20);
124 |
125 | callback.Invoke(currentAccess.Access, null);
126 | return;
127 | }
128 |
129 | // If there's a player limit
130 | if (Options.MaxPlayers != 0)
131 | {
132 | var playerSlotsTaken = _pendingRequests.Count
133 | + _accessesInUse.Count
134 | + _unconfirmedAccesses.Count;
135 |
136 | if (playerSlotsTaken >= Options.MaxPlayers)
137 | {
138 | callback.Invoke(null, "Room is already full");
139 | return;
140 | }
141 | }
142 |
143 | var packet = new RoomAccessProvideCheckPacket
144 | {
145 | ClientID = client.ID,
146 | RoomID = ID
147 | };
148 |
149 | // Add to pending list
150 | _pendingRequests[client] = callback;
151 |
152 | Client.SendMessage(Message.Create(MessageTags.ProvideRoomAccessCheck, packet), SendMode.Reliable);
153 | }
154 |
155 | public bool ValidateAccess(string token, out IClient client)
156 | {
157 | _unconfirmedAccesses.TryGetValue(token, out var data);
158 |
159 | client = null;
160 |
161 | if (data == null)
162 | return false;
163 |
164 | _unconfirmedAccesses.Remove(token);
165 |
166 | if (!data.Client.IsConnected)
167 | return false;
168 |
169 | _accessesInUse.Add(data.Client.ID, data.Access);
170 |
171 | client = data.Client;
172 |
173 | return true;
174 | }
175 |
176 | public void ClearTimedOutAccesses()
177 | {
178 | var timedOut = _unconfirmedAccesses.Values.Where(u => u.Timeout < DateTime.Now).ToList();
179 |
180 | foreach (var access in timedOut)
181 | _unconfirmedAccesses.Remove(access.Access.Token);
182 | }
183 |
184 | public void OnPlayerLeft(int peerId)
185 | {
186 | _accessesInUse.Remove(peerId);
187 |
188 | _players.TryGetValue(peerId, out var playerPeer);
189 |
190 | if (playerPeer == null)
191 | return;
192 | }
193 |
194 | public void Destroy()
195 | {
196 | _unconfirmedAccesses.Clear();
197 |
198 | }
199 |
200 | private class RoomAccessData
201 | {
202 | public RoomAccessPacket Access;
203 | public IClient Client;
204 | public DateTime Timeout;
205 | }
206 | }
207 | }
--------------------------------------------------------------------------------
/ServerPlugins/RoomHandler/RoomHandlerPlugin.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading;
5 | using System.Threading.Tasks;
6 | using DarkRift;
7 | using DarkRift.Server;
8 | using Utils;
9 | using Utils.Messages.Responses;
10 | using Utils.Packets;
11 |
12 | namespace ServerPlugins.RoomHandler
13 | {
14 | public class RoomHandlerPlugin : ServerPluginBase
15 | {
16 | private int _nextRoomID;
17 | private readonly List _rooms;
18 |
19 | public override bool ThreadSafe => false;
20 |
21 | public RoomHandlerPlugin(PluginLoadData pluginLoadData) : base(pluginLoadData)
22 | {
23 | _rooms = new List();
24 | ClientManager.ClientDisconnected += OnClientDisconnected;
25 | }
26 | protected override void Loaded(LoadedEventArgs args)
27 | {
28 | base.Loaded(args);
29 | SetHandler(MessageTags.RegisterRoom, HandleRegisterRoom);
30 | SetHandler(MessageTags.GetRoomAccess, HandleGetRoomAccess);
31 | SetHandler(MessageTags.ValidateRoomAccess, HandleValidateRoomAccess);
32 | SetHandler(MessageTags.GetRooms, HandleGetRooms);
33 |
34 | Task.Run(() => CleanUnconfirmedAccesses());
35 | }
36 |
37 | private void HandleGetRooms(IClient client, Message message)
38 | {
39 | var publicGames = _rooms.Where(r => r.Options.IsPublic)
40 | .GroupBy(room => room.Options.WorldName, room => room, (s, rooms) => new { WorldName = s, Rooms = rooms})
41 | .Select(worldInfo => new GameInfo
42 | {
43 | //TODO: multiple rooms per world
44 | Name = worldInfo.WorldName,
45 | ID = worldInfo.Rooms.First().ID,
46 | OnlinePlayers = worldInfo.Rooms.First().OnlineCount,
47 | MaxPlayers = worldInfo.Rooms.First().Options.MaxPlayers,
48 | }).ToList();
49 | client.SendMessage(Message.Create(MessageTags.GetRooms, new GameInfoPacket()
50 | {
51 | Games = publicGames
52 | }), SendMode.Reliable);
53 | }
54 |
55 | private void CleanUnconfirmedAccesses()
56 | {
57 | while (true)
58 | {
59 | Thread.Sleep(TimeSpan.FromSeconds(1));
60 |
61 | foreach (var registeredRoom in _rooms)
62 | {
63 | registeredRoom.ClearTimedOutAccesses();
64 | }
65 | }
66 | }
67 |
68 | private void OnClientDisconnected(object sender, ClientDisconnectedEventArgs e)
69 | {
70 | foreach (var room in _rooms.Where(registeredRoom => registeredRoom.Client.ID == e.Client.ID))
71 | {
72 | room.Destroy();
73 | }
74 | // Remove the room from all rooms
75 | _rooms.RemoveAll(room => room.Client.ID == e.Client.ID);
76 | }
77 |
78 | private void HandleValidateRoomAccess(IClient client, Message message)
79 | {
80 | var data = message.Deserialize();
81 | if (data != null)
82 | {
83 | var room = _rooms.FirstOrDefault(registeredRoom => registeredRoom.ID == data.RoomID);
84 |
85 | if (room == null)
86 | {
87 | client.SendMessage(Message.Create(MessageTags.ValidateRoomAccessFailed, new IntPacket {Data = data.ClientID }), SendMode.Reliable);
88 | return;
89 | }
90 |
91 | if (client != room.Client)
92 | {
93 | client.SendMessage(Message.Create(MessageTags.ValidateRoomAccessFailed, new IntPacket { Data = data.ClientID }), SendMode.Reliable);
94 | return;
95 | }
96 |
97 |
98 | if (!room.ValidateAccess(data.Token, out var playerClient))
99 | {
100 | client.SendMessage(Message.Create(MessageTags.ValidateRoomAccessFailed, new IntPacket { Data = data.ClientID }), SendMode.Reliable);
101 | return;
102 | }
103 |
104 | // Respond with success and player's peer id
105 | client.SendMessage(Message.Create(MessageTags.ValidateRoomAccessSuccess,
106 | new RoomAccessValidatedPacket
107 | {
108 | ClientID = data.ClientID,
109 | MasterClientID = playerClient.ID,
110 |
111 | }), SendMode.Reliable);
112 | }
113 | }
114 |
115 | private void HandleGetRoomAccess(IClient client, Message message)
116 | {
117 | var data = message.Deserialize();
118 | if (data != null)
119 | {
120 | var room = _rooms.FirstOrDefault(registeredRoom => registeredRoom.ID == data.RoomId);
121 |
122 | if (room == null)
123 | {
124 | client.SendMessage(
125 | Message.Create(MessageTags.GetRoomAccessFailed,
126 | new FailedMessage {Reason = "Room does not exist", Status = ResponseStatus.Failed}),
127 | SendMode.Reliable);
128 | return;
129 | }
130 |
131 | // Send room access request to peer who owns it
132 | room.GetAccess(client, (packet, error) =>
133 | {
134 | if (packet == null)
135 | {
136 | client.SendMessage(Message.Create(MessageTags.GetRoomAccessFailed, new FailedMessage {Reason = "Access denied", Status = ResponseStatus.Unauthorized}), SendMode.Reliable);
137 | return;
138 | }
139 |
140 | client.SendMessage(Message.Create(MessageTags.GetRoomAccessSuccess, packet), SendMode.Reliable);
141 | });
142 | }
143 | }
144 |
145 | private void HandleRegisterRoom(IClient client, Message message)
146 | {
147 | if (!HasRoomRegistrationPermissions(client))
148 | {
149 | client.SendMessage(
150 | Message.Create(MessageTags.RegisterRoomFailed,
151 | new FailedMessage { Reason = "Insufficient permissions", Status = ResponseStatus.Unauthorized }),
152 | SendMode.Reliable);
153 | return;
154 | }
155 |
156 | var data = message.Deserialize();
157 | if (data != null)
158 | {
159 |
160 | var room = RegisterRoom(client, data);
161 |
162 | // Respond with a room id
163 | client.SendMessage(Message.Create(MessageTags.RegisterRoomSuccess, new RegisterRoomSuccessMessage { Status = ResponseStatus.Success, RoomID = room.ID }),
164 | SendMode.Reliable);
165 | }
166 | else
167 | {
168 | client.SendMessage(
169 | Message.Create(MessageTags.RegisterRoomFailed,
170 | new FailedMessage { Reason = "Unable to read data", Status = ResponseStatus.Failed }),
171 | SendMode.Reliable);
172 | }
173 | }
174 |
175 | private bool HasRoomRegistrationPermissions(IClient client)
176 | {
177 | //TODO: Check room-register permissions
178 | return true;
179 | }
180 |
181 | private RegisteredRoom RegisterRoom(IClient client, RoomOptions options)
182 | {
183 | // Create the object
184 | var room = new RegisteredRoom(GenerateRoomId(), client, options);
185 |
186 |
187 | // Add the room to a list of all rooms
188 | _rooms.Add(room);
189 |
190 | return room;
191 | }
192 |
193 | private int GenerateRoomId()
194 | {
195 | //return Interlocked.Increment(ref _nextRoomID);
196 | return _nextRoomID++;
197 | }
198 | }
199 | }
--------------------------------------------------------------------------------
/ServerPlugins/ServerPluginBase.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using DarkRift;
4 | using DarkRift.Server;
5 |
6 | namespace ServerPlugins
7 | {
8 |
9 | public delegate void MessageHandler(IClient client, Message message);
10 |
11 | public abstract class ServerPluginBase : Plugin
12 | {
13 | public override bool ThreadSafe => true;
14 | public override Version Version => new Version(1, 0, 0);
15 |
16 | private readonly Dictionary _handlers;
17 |
18 | protected ServerPluginBase(PluginLoadData pluginLoadData) : base(pluginLoadData)
19 | {
20 | _handlers = new Dictionary();
21 | ClientManager.ClientConnected += OnClientConnected;
22 | }
23 |
24 | protected virtual void OnClientConnected(object sender, ClientConnectedEventArgs e)
25 | {
26 | e.Client.MessageReceived += OnMessagereceived;
27 | }
28 |
29 | private void OnMessagereceived(object sender, MessageReceivedEventArgs e)
30 | {
31 | var message = e.GetMessage();
32 |
33 | if (message != null)
34 | {
35 | WriteEvent("Received message with tag " + message.Tag, LogType.Trace);
36 | if (_handlers.ContainsKey(message.Tag))
37 | {
38 | _handlers[message.Tag](e.Client, message);
39 | }
40 | }
41 | else
42 | {
43 |
44 | WriteEvent("Received message null", LogType.Trace);
45 | }
46 | }
47 |
48 | protected void SetHandler(ushort tag, MessageHandler handler)
49 | {
50 | _handlers[tag] = handler;
51 | }
52 | }
53 | }
--------------------------------------------------------------------------------
/ServerPlugins/ServerPlugins.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {3F3234EE-ED0E-44E3-8024-05CC293F568E}
8 | Library
9 | Properties
10 | ServerPlugins
11 | ServerPlugins
12 | v4.6
13 | 512
14 |
15 |
16 |
17 | true
18 | full
19 | false
20 | bin\Debug\
21 | DEBUG;TRACE
22 | prompt
23 | 4
24 | false
25 |
26 |
27 | pdbonly
28 | true
29 | bin\Release\
30 | TRACE
31 | prompt
32 | 4
33 | false
34 |
35 |
36 |
37 | False
38 | ..\Deploy\Lib\DarkRift.dll
39 |
40 |
41 | ..\Deploy\Lib\DarkRift.Client.dll
42 |
43 |
44 | False
45 | ..\Deploy\Lib\DarkRift.Server.dll
46 |
47 |
48 | ..\packages\MathFloat.1.0.1.0\lib\net20\MathFloat.dll
49 |
50 |
51 |
52 | ..\packages\MySql.Data.6.10.6\lib\net452\MySql.Data.dll
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 | {6c4bedd5-f000-4994-b000-2f5f310f6e3a}
98 | RecastDetour
99 |
100 |
101 | {73957A5C-7298-4BD7-97A7-6E572B50D155}
102 | Utils
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 | taskkill /F /IM "DarkRift.Server.Console.exe"
114 | taskkill /F /IM "Spawner.exe"
115 | xcopy /d /y $(ProjectDir)bin\$(ConfigurationName) $(SolutionDir)\Deploy\Plugins\
116 | xcopy /d /y $(ProjectDir)bin\$(ConfigurationName)\Game\Levels $(SolutionDir)\Deploy\Levels\
117 |
118 |
--------------------------------------------------------------------------------
/ServerPlugins/SpawnerHandler/RegisteredSpawner.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 | using DarkRift;
4 | using DarkRift.Server;
5 | using Utils;
6 | using Utils.Messages;
7 | using Utils.Packets;
8 |
9 | namespace ServerPlugins.SpawnerHandler
10 | {
11 | public class RegisteredSpawner
12 | {
13 | public delegate void KillRequestCallback(bool isKilled);
14 |
15 | public static int MaxConcurrentRequests = 8;
16 | private readonly HashSet _beingSpawned;
17 |
18 | private readonly Queue _queue;
19 | private readonly HashSet _startingProcesses;
20 |
21 | public int ID { get; set; }
22 | public IClient Client { get; set; }
23 | public SpawnerOptions Options { get; set; }
24 |
25 | public int ProcessesRunning { get; private set; }
26 |
27 | public RegisteredSpawner(int id, IClient client, SpawnerOptions options)
28 | {
29 | ID = id;
30 | Client = client;
31 | Options = options;
32 |
33 | _queue = new Queue();
34 | _beingSpawned = new HashSet();
35 | }
36 |
37 | public int CalculateFreeSlotsCount()
38 | {
39 | return Options.MaxProcesses - _queue.Count - ProcessesRunning;
40 | }
41 |
42 | public bool CanSpawnAnotherProcess()
43 | {
44 | // Unlimited
45 | if (Options.MaxProcesses == 0)
46 | return true;
47 |
48 | // Spawner is busy
49 | if (_queue.Count + ProcessesRunning >= Options.MaxProcesses)
50 | return false;
51 |
52 | return true;
53 | }
54 |
55 | public void AddTaskToQueue(SpawnTask task)
56 | {
57 | _queue.Enqueue(task);
58 | }
59 |
60 | public void UpdateQueue()
61 | {
62 | // Ignore if there's no connection with the peer
63 | if (!Client.IsConnected)
64 | return;
65 |
66 | // Ignore if nothing's in the queue
67 | if (_queue.Count == 0)
68 | return;
69 |
70 | if (_beingSpawned.Count >= MaxConcurrentRequests)
71 | {
72 | // If we're currently at the maximum available concurrent spawn count
73 | var finishedSpawns = _beingSpawned.Where(s => s.IsDoneStartingProcess);
74 |
75 | // Remove finished spawns
76 | foreach (var finishedSpawn in finishedSpawns)
77 | _beingSpawned.Remove(finishedSpawn);
78 | }
79 |
80 | // If we're still at the maximum concurrent requests
81 | if (_beingSpawned.Count >= MaxConcurrentRequests)
82 | return;
83 |
84 | var task = _queue.Dequeue();
85 |
86 | var data = new SpawnRequestPacket
87 | {
88 | SpawnerId = ID,
89 | SpawnTaskID = task.ID,
90 | SpawnCode = task.UniqueCode,
91 | Options = task.Options
92 | };
93 |
94 | Client.SendMessage(Message.Create(MessageTags.RequestSpawnFromMasterToSpawner, data), SendMode.Reliable);
95 | }
96 |
97 | public void SendKillRequest(int spawnId, KillRequestCallback callback)
98 | {
99 | var packet = new KillSpawnedProcessPacket
100 | {
101 | SpawnerId = ID,
102 | SpawnId = spawnId
103 | };
104 |
105 | Client.SendMessage(Message.Create(MessageTags.KillSpawn, packet), SendMode.Reliable);
106 | }
107 |
108 | public void OnProcessKilled()
109 | {
110 | ProcessesRunning -= 1;
111 | }
112 |
113 | public void OnProcessStarted()
114 | {
115 | ProcessesRunning += 1;
116 | }
117 |
118 | public override string ToString()
119 | {
120 | return Options.Region + "-" + ID;
121 | }
122 | }
123 | }
--------------------------------------------------------------------------------
/ServerPlugins/SpawnerHandler/SpawnTask.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using DarkRift.Server;
4 | using Utils;
5 | using Utils.Messages.Notifications;
6 |
7 | namespace ServerPlugins.SpawnerHandler
8 | {
9 | ///
10 | /// Represents a spawn request, and manages the state of request
11 | /// from start to finalization
12 | ///
13 | public class SpawnTask
14 | {
15 | private SpawnStatus _status;
16 |
17 | protected List> WhenDoneCallbacks;
18 |
19 | public RegisteredSpawner Spawner { get; }
20 | public RoomOptions Options { get; }
21 |
22 | public int ID { get; }
23 |
24 | public string UniqueCode { get; }
25 |
26 | public SpawnFinalizedMessage FinalizationMessage { get; private set; }
27 |
28 | public bool IsAborted => _status < SpawnStatus.None;
29 |
30 | public bool IsDoneStartingProcess => IsAborted || IsProcessStarted;
31 |
32 | public bool IsProcessStarted => Status >= SpawnStatus.WaitingForProcess;
33 |
34 | public SpawnStatus Status
35 | {
36 | get => _status;
37 | set
38 | {
39 | _status = value;
40 |
41 | if (StatusChanged != null)
42 | StatusChanged.Invoke(_status);
43 |
44 | if (_status >= SpawnStatus.Finalized || _status < SpawnStatus.None)
45 | NotifyDoneListeners();
46 | }
47 | }
48 |
49 | ///
50 | /// Peer, who registered a started process for this task
51 | /// (for example, a game server)
52 | ///
53 | public IClient RegisteredClient { get; private set; }
54 |
55 | ///
56 | /// Who requested to spawn
57 | /// (most likely clients peer)
58 | /// Can be null
59 | ///
60 | public IClient Requester { get; set; }
61 |
62 | public SpawnTask(int id, RegisteredSpawner spawner, RoomOptions options)
63 | {
64 | ID = id;
65 |
66 | Spawner = spawner;
67 | Options = options;
68 |
69 | UniqueCode = Security.CreateRandomString(6);
70 | WhenDoneCallbacks = new List>();
71 | }
72 |
73 | public event Action StatusChanged;
74 |
75 | public void OnProcessStarted()
76 | {
77 | if (!IsAborted && Status < SpawnStatus.WaitingForProcess)
78 | {
79 | Status = SpawnStatus.WaitingForProcess;
80 | Spawner.OnProcessStarted();
81 | }
82 | }
83 |
84 | public void OnProcessKilled()
85 | {
86 | Status = SpawnStatus.Killed;
87 | Spawner.OnProcessKilled();
88 | }
89 |
90 | public void OnRegistered(IClient clientWhoRegistered)
91 | {
92 | RegisteredClient = clientWhoRegistered;
93 |
94 | if (!IsAborted && Status < SpawnStatus.ProcessRegistered) Status = SpawnStatus.ProcessRegistered;
95 | }
96 |
97 | public void OnFinalized(SpawnFinalizedMessage finalizedMessage)
98 | {
99 | FinalizationMessage = finalizedMessage;
100 | if (!IsAborted && Status < SpawnStatus.Finalized) Status = SpawnStatus.Finalized;
101 | }
102 |
103 | public override string ToString()
104 | {
105 | return $"[SpawnTask: id - {ID}]";
106 | }
107 |
108 | protected void NotifyDoneListeners()
109 | {
110 | foreach (var callback in WhenDoneCallbacks) callback.Invoke(this);
111 |
112 | WhenDoneCallbacks.Clear();
113 | }
114 |
115 | ///
116 | /// Callback will be called when spawn task is aborted or completed
117 | /// (game server is opened)
118 | ///
119 | ///
120 | public SpawnTask WhenDone(Action callback)
121 | {
122 | WhenDoneCallbacks.Add(callback);
123 | return this;
124 | }
125 |
126 | public void Abort()
127 | {
128 | if (Status >= SpawnStatus.Finalized)
129 | return;
130 |
131 | Status = SpawnStatus.Aborting;
132 |
133 | KillSpawnedProcess();
134 | }
135 |
136 | public void KillSpawnedProcess()
137 | {
138 | Spawner.SendKillRequest(ID, killed =>
139 | {
140 | Status = SpawnStatus.Aborted;
141 |
142 | if (!killed)
143 | throw new Exception("Spawned Process might not have been killed");
144 | });
145 | }
146 | }
147 | }
--------------------------------------------------------------------------------
/ServerPlugins/Time/TimePlugin.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using DarkRift;
3 | using DarkRift.Server;
4 | using Utils;
5 | using Utils.Packets;
6 |
7 | namespace ServerPlugins.Time
8 | {
9 | ///
10 | /// This Plugin goes to the spawned server
11 | ///
12 | public class TimePlugin : ServerPluginBase
13 | {
14 | //time since this plugin was loaded
15 | private readonly long _startTime;
16 |
17 |
18 | public TimePlugin(PluginLoadData pluginLoadData) : base(pluginLoadData)
19 | {
20 | _startTime = DateTime.Now.Ticks;
21 | }
22 |
23 |
24 | protected override void Loaded(LoadedEventArgs args)
25 | {
26 | base.Loaded(args);
27 | SetHandler(MessageTags.GetNetworkTime, HandleGetNetworkTime);
28 | }
29 |
30 | private void HandleGetNetworkTime(IClient client, Message message)
31 | {
32 | client.SendMessage(Message.Create(MessageTags.GetNetworkTime,
33 | new FloatPacket {Data = (float) TimeSpan.FromTicks(DateTime.Now.Ticks - _startTime).TotalSeconds}),
34 | SendMode.Reliable);
35 | }
36 | }
37 | }
--------------------------------------------------------------------------------
/ServerPlugins/app.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/ServerPlugins/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/Spawner/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.InteropServices;
3 |
4 | // General Information about an assembly is controlled through the following
5 | // set of attributes. Change these attribute values to modify the information
6 | // associated with an assembly.
7 | [assembly: AssemblyTitle("Spawner")]
8 | [assembly: AssemblyDescription("")]
9 | [assembly: AssemblyConfiguration("")]
10 | [assembly: AssemblyCompany("")]
11 | [assembly: AssemblyProduct("Spawner")]
12 | [assembly: AssemblyCopyright("Copyright © 2018")]
13 | [assembly: AssemblyTrademark("")]
14 | [assembly: AssemblyCulture("")]
15 |
16 | // Setting ComVisible to false makes the types in this assembly not visible
17 | // to COM components. If you need to access a type in this assembly from
18 | // COM, set the ComVisible attribute to true on that type.
19 | [assembly: ComVisible(false)]
20 |
21 | // The following GUID is for the ID of the typelib if this project is exposed to COM
22 | [assembly: Guid("733a5630-dee5-4ac2-8445-7886d853a349")]
23 |
24 | // Version information for an assembly consists of the following four values:
25 | //
26 | // Major Version
27 | // Minor Version
28 | // Build Number
29 | // Revision
30 | //
31 | // You can specify all the values or you can default the Build and Revision Numbers
32 | // by using the '*' as shown below:
33 | // [assembly: AssemblyVersion("1.0.*")]
34 | [assembly: AssemblyVersion("1.0.0.0")]
35 | [assembly: AssemblyFileVersion("1.0.0.0")]
--------------------------------------------------------------------------------
/Spawner/Properties/Settings.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.42000
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace Spawner.Properties {
12 |
13 |
14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.6.0.0")]
16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
17 |
18 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
19 |
20 | public static Settings Default {
21 | get {
22 | return defaultInstance;
23 | }
24 | }
25 |
26 | [global::System.Configuration.ApplicationScopedSettingAttribute()]
27 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
28 | [global::System.Configuration.DefaultSettingValueAttribute("DarkRift.Server.Console.exe")]
29 | public string ExecutablePath {
30 | get {
31 | return ((string)(this["ExecutablePath"]));
32 | }
33 | }
34 |
35 | [global::System.Configuration.ApplicationScopedSettingAttribute()]
36 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
37 | [global::System.Configuration.DefaultSettingValueAttribute("WorldServer.config")]
38 | public string ConfigPath {
39 | get {
40 | return ((string)(this["ConfigPath"]));
41 | }
42 | }
43 |
44 | [global::System.Configuration.ApplicationScopedSettingAttribute()]
45 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
46 | [global::System.Configuration.DefaultSettingValueAttribute("127.0.0.1")]
47 | public string MasterIpAddress {
48 | get {
49 | return ((string)(this["MasterIpAddress"]));
50 | }
51 | }
52 |
53 | [global::System.Configuration.ApplicationScopedSettingAttribute()]
54 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
55 | [global::System.Configuration.DefaultSettingValueAttribute("60125")]
56 | public string MasterPort {
57 | get {
58 | return ((string)(this["MasterPort"]));
59 | }
60 | }
61 |
62 | [global::System.Configuration.ApplicationScopedSettingAttribute()]
63 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
64 | [global::System.Configuration.DefaultSettingValueAttribute("EU")]
65 | public string Region {
66 | get {
67 | return ((string)(this["Region"]));
68 | }
69 | }
70 |
71 | [global::System.Configuration.ApplicationScopedSettingAttribute()]
72 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
73 | [global::System.Configuration.DefaultSettingValueAttribute("True")]
74 | public bool AutoStartSpawner {
75 | get {
76 | return ((bool)(this["AutoStartSpawner"]));
77 | }
78 | }
79 |
80 | [global::System.Configuration.ApplicationScopedSettingAttribute()]
81 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
82 | [global::System.Configuration.DefaultSettingValueAttribute("0.0.0.0")]
83 | public string SpawnerIpAddress {
84 | get {
85 | return ((string)(this["SpawnerIpAddress"]));
86 | }
87 | }
88 |
89 | [global::System.Configuration.ApplicationScopedSettingAttribute()]
90 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
91 | [global::System.Configuration.DefaultSettingValueAttribute("20000")]
92 | public int SpawnerStartPort {
93 | get {
94 | return ((int)(this["SpawnerStartPort"]));
95 | }
96 | }
97 |
98 | [global::System.Configuration.ApplicationScopedSettingAttribute()]
99 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
100 | [global::System.Configuration.DefaultSettingValueAttribute("10")]
101 | public int MaxProcesses {
102 | get {
103 | return ((int)(this["MaxProcesses"]));
104 | }
105 | }
106 |
107 | [global::System.Configuration.ApplicationScopedSettingAttribute()]
108 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
109 | [global::System.Configuration.DefaultSettingValueAttribute("True")]
110 | public bool UseShellExecute {
111 | get {
112 | return ((bool)(this["UseShellExecute"]));
113 | }
114 | }
115 |
116 | [global::System.Configuration.ApplicationScopedSettingAttribute()]
117 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
118 | [global::System.Configuration.DefaultSettingValueAttribute("True")]
119 | public bool CreateRoomWindow {
120 | get {
121 | return ((bool)(this["CreateRoomWindow"]));
122 | }
123 | }
124 |
125 | [global::System.Configuration.ApplicationScopedSettingAttribute()]
126 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
127 | [global::System.Configuration.DefaultSettingValueAttribute("False")]
128 | public bool UseMono {
129 | get {
130 | return ((bool)(this["UseMono"]));
131 | }
132 | }
133 | }
134 | }
135 |
--------------------------------------------------------------------------------
/Spawner/Properties/Settings.settings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | DarkRift.Server.Console.exe
7 |
8 |
9 | WorldServer.config
10 |
11 |
12 | 127.0.0.1
13 |
14 |
15 | 60125
16 |
17 |
18 | EU
19 |
20 |
21 | True
22 |
23 |
24 | 0.0.0.0
25 |
26 |
27 | 20000
28 |
29 |
30 | 10
31 |
32 |
33 | True
34 |
35 |
36 | True
37 |
38 |
39 | False
40 |
41 |
42 |
--------------------------------------------------------------------------------
/Spawner/Spawner.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {733A5630-DEE5-4AC2-8445-7886D853A349}
8 | Exe
9 | Spawner
10 | Spawner
11 | v4.6
12 | 512
13 |
14 |
15 |
16 | AnyCPU
17 | true
18 | full
19 | false
20 | bin\Debug\
21 | DEBUG;TRACE
22 | prompt
23 | 4
24 | false
25 |
26 |
27 | AnyCPU
28 | pdbonly
29 | true
30 | bin\Release\
31 | TRACE
32 | prompt
33 | 4
34 | false
35 |
36 |
37 | OnOutputUpdated
38 |
39 |
40 |
41 | ..\Deploy\Lib\DarkRift.dll
42 |
43 |
44 | ..\Deploy\Lib\DarkRift.Client.dll
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 | True
56 | True
57 | Settings.settings
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 | SettingsSingleFileGenerator
67 | Settings.Designer.cs
68 |
69 |
70 |
71 |
72 | {73957A5C-7298-4BD7-97A7-6E572B50D155}
73 | Utils
74 |
75 |
76 |
77 |
78 | xcopy /d /y $(TargetDir)$(TargetName).exe $(SolutionDir)\Deploy\
79 | xcopy /d /y $(TargetDir)$(TargetName).pdb $(SolutionDir)\Deploy\
80 | xcopy /d /y $(TargetDir)$(TargetName).exe.config $(SolutionDir)\Deploy\
81 |
82 |
--------------------------------------------------------------------------------
/Spawner/SpawnerOptions.cs:
--------------------------------------------------------------------------------
1 | using DarkRift;
2 |
3 | namespace Spawner
4 | {
5 | public class SpawnerOptions : IDarkRiftSerializable
6 | {
7 | public string MachineIp = "xxx.xxx.xxx.xxx";
8 |
9 | public int MaxProcesses;
10 |
11 | public string Region = "International";
12 |
13 | public void Deserialize(DeserializeEvent e)
14 | {
15 | MachineIp = e.Reader.ReadString();
16 | MaxProcesses = e.Reader.ReadInt32();
17 | Region = e.Reader.ReadString();
18 | }
19 |
20 | public void Serialize(SerializeEvent e)
21 | {
22 | e.Writer.Write(MachineIp);
23 | e.Writer.Write(MaxProcesses);
24 | e.Writer.Write(Region);
25 | }
26 |
27 | public override string ToString()
28 | {
29 | return $"PublicIp: {MachineIp}, MaxProcesses: {MaxProcesses}, Region: {Region}";
30 | }
31 | }
32 | }
--------------------------------------------------------------------------------
/Spawner/app.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | DarkRift.Server.Console.exe
12 |
13 |
14 | WorldServer.config
15 |
16 |
17 | 127.0.0.1
18 |
19 |
20 | 60125
21 |
22 |
23 | EU
24 |
25 |
26 | True
27 |
28 |
29 | 0.0.0.0
30 |
31 |
32 | 20000
33 |
34 |
35 | 10
36 |
37 |
38 | True
39 |
40 |
41 | True
42 |
43 |
44 | False
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/TundraClientExample/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.InteropServices;
3 |
4 | // General Information about an assembly is controlled through the following
5 | // set of attributes. Change these attribute values to modify the information
6 | // associated with an assembly.
7 | [assembly: AssemblyTitle("UnityClientExample")]
8 | [assembly: AssemblyDescription("")]
9 | [assembly: AssemblyConfiguration("")]
10 | [assembly: AssemblyCompany("")]
11 | [assembly: AssemblyProduct("UnityClientExample")]
12 | [assembly: AssemblyCopyright("Copyright © 2018")]
13 | [assembly: AssemblyTrademark("")]
14 | [assembly: AssemblyCulture("")]
15 |
16 | // Setting ComVisible to false makes the types in this assembly not visible
17 | // to COM components. If you need to access a type in this assembly from
18 | // COM, set the ComVisible attribute to true on that type.
19 | [assembly: ComVisible(false)]
20 |
21 | // The following GUID is for the ID of the typelib if this project is exposed to COM
22 | [assembly: Guid("293d0bb8-6f23-47e0-8047-def7afe92464")]
23 |
24 | // Version information for an assembly consists of the following four values:
25 | //
26 | // Major Version
27 | // Minor Version
28 | // Build Number
29 | // Revision
30 | //
31 | // You can specify all the values or you can default the Build and Revision Numbers
32 | // by using the '*' as shown below:
33 | // [assembly: AssemblyVersion("1.0.*")]
34 | [assembly: AssemblyVersion("1.0.0.0")]
35 | [assembly: AssemblyFileVersion("1.0.0.0")]
--------------------------------------------------------------------------------
/TundraClientExample/TundraClient.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {293D0BB8-6F23-47E0-8047-DEF7AFE92464}
8 | Library
9 | Properties
10 | Tundra
11 | Tundra
12 | v3.5
13 | 512
14 |
15 |
16 | true
17 | full
18 | false
19 | bin\Debug\
20 | DEBUG;TRACE
21 | prompt
22 | 4
23 |
24 |
25 | pdbonly
26 | true
27 | bin\Release\
28 | TRACE
29 | prompt
30 | 4
31 |
32 |
33 | OnBuildSuccess
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/TundraServerPlugins.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.27428.1
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Utils", "Utils\Utils.csproj", "{73957A5C-7298-4BD7-97A7-6E572B50D155}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TundraClient", "TundraClientExample\TundraClient.csproj", "{293D0BB8-6F23-47E0-8047-DEF7AFE92464}"
9 | EndProject
10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Spawner", "Spawner\Spawner.csproj", "{733A5630-DEE5-4AC2-8445-7886D853A349}"
11 | EndProject
12 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServerPlugins", "ServerPlugins\ServerPlugins.csproj", "{3F3234EE-ED0E-44E3-8024-05CC293F568E}"
13 | EndProject
14 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RecastDetour", "RecastDetour\RecastDetour.csproj", "{6C4BEDD5-F000-4994-B000-2F5F310F6E3A}"
15 | EndProject
16 | Global
17 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
18 | Debug|Any CPU = Debug|Any CPU
19 | Release|Any CPU = Release|Any CPU
20 | EndGlobalSection
21 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
22 | {73957A5C-7298-4BD7-97A7-6E572B50D155}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
23 | {73957A5C-7298-4BD7-97A7-6E572B50D155}.Debug|Any CPU.Build.0 = Debug|Any CPU
24 | {73957A5C-7298-4BD7-97A7-6E572B50D155}.Release|Any CPU.ActiveCfg = Release|Any CPU
25 | {73957A5C-7298-4BD7-97A7-6E572B50D155}.Release|Any CPU.Build.0 = Release|Any CPU
26 | {293D0BB8-6F23-47E0-8047-DEF7AFE92464}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
27 | {293D0BB8-6F23-47E0-8047-DEF7AFE92464}.Debug|Any CPU.Build.0 = Debug|Any CPU
28 | {293D0BB8-6F23-47E0-8047-DEF7AFE92464}.Release|Any CPU.ActiveCfg = Release|Any CPU
29 | {293D0BB8-6F23-47E0-8047-DEF7AFE92464}.Release|Any CPU.Build.0 = Release|Any CPU
30 | {733A5630-DEE5-4AC2-8445-7886D853A349}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
31 | {733A5630-DEE5-4AC2-8445-7886D853A349}.Debug|Any CPU.Build.0 = Debug|Any CPU
32 | {733A5630-DEE5-4AC2-8445-7886D853A349}.Release|Any CPU.ActiveCfg = Release|Any CPU
33 | {733A5630-DEE5-4AC2-8445-7886D853A349}.Release|Any CPU.Build.0 = Release|Any CPU
34 | {3F3234EE-ED0E-44E3-8024-05CC293F568E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
35 | {3F3234EE-ED0E-44E3-8024-05CC293F568E}.Debug|Any CPU.Build.0 = Debug|Any CPU
36 | {3F3234EE-ED0E-44E3-8024-05CC293F568E}.Release|Any CPU.ActiveCfg = Release|Any CPU
37 | {3F3234EE-ED0E-44E3-8024-05CC293F568E}.Release|Any CPU.Build.0 = Release|Any CPU
38 | {6C4BEDD5-F000-4994-B000-2F5F310F6E3A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
39 | {6C4BEDD5-F000-4994-B000-2F5F310F6E3A}.Debug|Any CPU.Build.0 = Debug|Any CPU
40 | {6C4BEDD5-F000-4994-B000-2F5F310F6E3A}.Release|Any CPU.ActiveCfg = Release|Any CPU
41 | {6C4BEDD5-F000-4994-B000-2F5F310F6E3A}.Release|Any CPU.Build.0 = Release|Any CPU
42 | EndGlobalSection
43 | GlobalSection(SolutionProperties) = preSolution
44 | HideSolutionNode = FALSE
45 | EndGlobalSection
46 | GlobalSection(ExtensibilityGlobals) = postSolution
47 | SolutionGuid = {19BB174A-E3E6-4F30-9797-68593BB08AAC}
48 | EndGlobalSection
49 | EndGlobal
50 |
--------------------------------------------------------------------------------
/Utils/ArgNames.cs:
--------------------------------------------------------------------------------
1 | namespace Utils
2 | {
3 | public class ArgNames
4 | {
5 | public const string MasterPort = "-MasterPort";
6 | public const string MasterIpAddress = "-MasterIpAddress";
7 | public const string SpawnTaskID = "-SpawnTaskID";
8 | public const string SpawnCode = "-SpawnCode";
9 | public const string AssignedPort = "-AssignedPort";
10 | public const string MachineIp = "-MachineIp";
11 | public const string WorldName = "-WorldName";
12 | public const string RoomName = "-RoomName";
13 | public const string MaxPlayers = "-MaxPlayers";
14 | public const string IsPublic = "-IsPublic";
15 | public const string Region = "-Region";
16 | }
17 | }
--------------------------------------------------------------------------------
/Utils/Conversion/BigEndianBitConverter.cs:
--------------------------------------------------------------------------------
1 | namespace Utils.Conversion
2 | {
3 | ///
4 | /// Implementation of EndianBitConverter which converts to/from big-endian
5 | /// byte arrays.
6 | ///
7 | public sealed class BigEndianBitConverter : EndianBitConverter
8 | {
9 | ///
10 | /// Indicates the byte order ("endianess") in which data is converted using this class.
11 | ///
12 | public override Endianness Endianness => Endianness.BigEndian;
13 |
14 | ///
15 | /// Indicates the byte order ("endianess") in which data is converted using this class.
16 | ///
17 | ///
18 | /// Different computer architectures store data using different byte orders. "Big-endian"
19 | /// means the most significant byte is on the left end of a word. "Little-endian" means the
20 | /// most significant byte is on the right end of a word.
21 | ///
22 | /// true if this converter is little-endian, false otherwise.
23 | public override bool IsLittleEndian()
24 | {
25 | return false;
26 | }
27 |
28 | ///
29 | /// Copies the specified number of bytes from value to buffer, starting at index.
30 | ///
31 | /// The value to copy
32 | /// The number of bytes to copy
33 | /// The buffer to copy the bytes into
34 | /// The index to start at
35 | protected override void CopyBytesImpl(long value, int bytes, byte[] buffer, int index)
36 | {
37 | var endOffset = index + bytes - 1;
38 | for (var i = 0; i < bytes; i++)
39 | {
40 | buffer[endOffset - i] = unchecked((byte) (value & 0xff));
41 | value = value >> 8;
42 | }
43 | }
44 |
45 | ///
46 | /// Returns a value built from the specified number of bytes from the given buffer,
47 | /// starting at index.
48 | ///
49 | /// The data in byte array format
50 | /// The first index to use
51 | /// The number of bytes to use
52 | /// The value built from the given bytes
53 | protected override long FromBytes(byte[] buffer, int startIndex, int bytesToConvert)
54 | {
55 | long ret = 0;
56 | for (var i = 0; i < bytesToConvert; i++)
57 | ret = unchecked((ret << 8) | buffer[startIndex + i]);
58 | return ret;
59 | }
60 | }
61 | }
--------------------------------------------------------------------------------
/Utils/Conversion/DoubleConverter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Globalization;
3 |
4 | namespace Utils.Conversion
5 | {
6 | ///
7 | /// A class to allow the conversion of doubles to string representations of
8 | /// their exact decimal values. The implementation aims for readability over
9 | /// efficiency.
10 | ///
11 | public class DoubleConverter
12 | {
13 | ///
14 | /// Converts the given double to a string representation of its
15 | /// exact decimal value.
16 | ///
17 | /// The double to convert.
18 | /// A string representation of the double's exact decimal value.
19 | public static string ToExactString(double d)
20 | {
21 | if (double.IsPositiveInfinity(d))
22 | return "+Infinity";
23 | if (double.IsNegativeInfinity(d))
24 | return "-Infinity";
25 | if (double.IsNaN(d))
26 | return "NaN";
27 |
28 | // Translate the double into sign, exponent and mantissa.
29 | var bits = BitConverter.DoubleToInt64Bits(d);
30 | var negative = bits < 0;
31 | var exponent = (int) ((bits >> 52) & 0x7ffL);
32 | var mantissa = bits & 0xfffffffffffffL;
33 |
34 | // Subnormal numbers; exponent is effectively one higher,
35 | // but there's no extra normalisation bit in the mantissa
36 | if (exponent == 0)
37 | exponent++;
38 | // Normal numbers; leave exponent as it is but add extra
39 | // bit to the front of the mantissa
40 | else
41 | mantissa = mantissa | (1L << 52);
42 |
43 | // Bias the exponent. It's actually biased by 1023, but we're
44 | // treating the mantissa as m.0 rather than 0.m, so we need
45 | // to subtract another 52 from it.
46 | exponent -= 1075;
47 |
48 | if (mantissa == 0)
49 | return "0";
50 |
51 | /* Normalize */
52 | while ((mantissa & 1) == 0)
53 | {
54 | /* i.e., Mantissa is even */
55 | mantissa >>= 1;
56 | exponent++;
57 | }
58 |
59 | // Construct a new decimal expansion with the mantissa
60 | var ad = new ArbitraryDecimal(mantissa);
61 |
62 | // If the exponent is less than 0, we need to repeatedly
63 | // divide by 2 - which is the equivalent of multiplying
64 | // by 5 and dividing by 10.
65 | if (exponent < 0)
66 | {
67 | for (var i = 0; i < -exponent; i++)
68 | ad.MultiplyBy(5);
69 | ad.Shift(-exponent);
70 | }
71 | // Otherwise, we need to repeatedly multiply by 2
72 | else
73 | {
74 | for (var i = 0; i < exponent; i++)
75 | ad.MultiplyBy(2);
76 | }
77 |
78 | // Finally, return the string with an appropriate sign
79 | if (negative)
80 | return "-" + ad;
81 | return ad.ToString();
82 | }
83 |
84 | ///
85 | /// Private class used for manipulating sequences of decimal digits.
86 | ///
87 | private class ArbitraryDecimal
88 | {
89 | ///
90 | /// How many digits are *after* the decimal point
91 | ///
92 | private int decimalPoint;
93 |
94 | /// Digits in the decimal expansion, one byte per digit
95 | private byte[] digits;
96 |
97 | ///
98 | /// Constructs an arbitrary decimal expansion from the given long.
99 | /// The long must not be negative.
100 | ///
101 | internal ArbitraryDecimal(long x)
102 | {
103 | var tmp = x.ToString(CultureInfo.InvariantCulture);
104 | digits = new byte[tmp.Length];
105 | for (var i = 0; i < tmp.Length; i++)
106 | digits[i] = (byte) (tmp[i] - '0');
107 | Normalize();
108 | }
109 |
110 | ///
111 | /// Multiplies the current expansion by the given amount, which should
112 | /// only be 2 or 5.
113 | ///
114 | internal void MultiplyBy(int amount)
115 | {
116 | var result = new byte[digits.Length + 1];
117 | for (var i = digits.Length - 1; i >= 0; i--)
118 | {
119 | var resultDigit = digits[i] * amount + result[i + 1];
120 | result[i] = (byte) (resultDigit / 10);
121 | result[i + 1] = (byte) (resultDigit % 10);
122 | }
123 |
124 | if (result[0] != 0)
125 | digits = result;
126 | else
127 | Array.Copy(result, 1, digits, 0, digits.Length);
128 | Normalize();
129 | }
130 |
131 | ///
132 | /// Shifts the decimal point; a negative value makes
133 | /// the decimal expansion bigger (as fewer digits come after the
134 | /// decimal place) and a positive value makes the decimal
135 | /// expansion smaller.
136 | ///
137 | internal void Shift(int amount)
138 | {
139 | decimalPoint += amount;
140 | }
141 |
142 | ///
143 | /// Removes leading/trailing zeroes from the expansion.
144 | ///
145 | internal void Normalize()
146 | {
147 | int first;
148 | for (first = 0; first < digits.Length; first++)
149 | if (digits[first] != 0)
150 | break;
151 | int last;
152 | for (last = digits.Length - 1; last >= 0; last--)
153 | if (digits[last] != 0)
154 | break;
155 |
156 | if (first == 0 && last == digits.Length - 1)
157 | return;
158 |
159 | var tmp = new byte[last - first + 1];
160 | for (var i = 0; i < tmp.Length; i++)
161 | tmp[i] = digits[i + first];
162 |
163 | decimalPoint -= digits.Length - (last + 1);
164 | digits = tmp;
165 | }
166 |
167 | ///
168 | /// Converts the value to a proper decimal string representation.
169 | ///
170 | public override string ToString()
171 | {
172 | var digitString = new char[digits.Length];
173 | for (var i = 0; i < digits.Length; i++)
174 | digitString[i] = (char) (digits[i] + '0');
175 |
176 | // Simplest case - nothing after the decimal point,
177 | // and last real digit is non-zero, eg value=35
178 | if (decimalPoint == 0)
179 | return new string(digitString);
180 |
181 | // Fairly simple case - nothing after the decimal
182 | // point, but some 0s to add, eg value=350
183 | if (decimalPoint < 0)
184 | return new string(digitString) +
185 | new string('0', -decimalPoint);
186 |
187 | // Nothing before the decimal point, eg 0.035
188 | if (decimalPoint >= digitString.Length)
189 | return "0." +
190 | new string('0', decimalPoint - digitString.Length) +
191 | new string(digitString);
192 |
193 | // Most complicated case - part of the string comes
194 | // before the decimal point, part comes after it,
195 | // eg 3.5
196 | return new string(digitString, 0,
197 | digitString.Length - decimalPoint) +
198 | "." +
199 | new string(digitString,
200 | digitString.Length - decimalPoint,
201 | decimalPoint);
202 | }
203 | }
204 | }
205 | }
--------------------------------------------------------------------------------
/Utils/Conversion/Endianness.cs:
--------------------------------------------------------------------------------
1 | namespace Utils.Conversion
2 | {
3 | ///
4 | /// Endianness of a converter
5 | ///
6 | public enum Endianness
7 | {
8 | ///
9 | /// Little endian - least significant byte first
10 | ///
11 | LittleEndian,
12 |
13 | ///
14 | /// Big endian - most significant byte first
15 | ///
16 | BigEndian
17 | }
18 | }
--------------------------------------------------------------------------------
/Utils/Conversion/LittleEndianBitConverter.cs:
--------------------------------------------------------------------------------
1 | namespace Utils.Conversion
2 | {
3 | ///
4 | /// Implementation of EndianBitConverter which converts to/from little-endian
5 | /// byte arrays.
6 | ///
7 | public sealed class LittleEndianBitConverter : EndianBitConverter
8 | {
9 | ///
10 | /// Indicates the byte order ("endianess") in which data is converted using this class.
11 | ///
12 | public override Endianness Endianness => Endianness.LittleEndian;
13 |
14 | ///
15 | /// Indicates the byte order ("endianess") in which data is converted using this class.
16 | ///
17 | ///
18 | /// Different computer architectures store data using different byte orders. "Big-endian"
19 | /// means the most significant byte is on the left end of a word. "Little-endian" means the
20 | /// most significant byte is on the right end of a word.
21 | ///
22 | /// true if this converter is little-endian, false otherwise.
23 | public override bool IsLittleEndian()
24 | {
25 | return true;
26 | }
27 |
28 | ///
29 | /// Copies the specified number of bytes from value to buffer, starting at index.
30 | ///
31 | /// The value to copy
32 | /// The number of bytes to copy
33 | /// The buffer to copy the bytes into
34 | /// The index to start at
35 | protected override void CopyBytesImpl(long value, int bytes, byte[] buffer, int index)
36 | {
37 | for (var i = 0; i < bytes; i++)
38 | {
39 | buffer[i + index] = unchecked((byte) (value & 0xff));
40 | value = value >> 8;
41 | }
42 | }
43 |
44 | ///
45 | /// Returns a value built from the specified number of bytes from the given buffer,
46 | /// starting at index.
47 | ///
48 | /// The data in byte array format
49 | /// The first index to use
50 | /// The number of bytes to use
51 | /// The value built from the given bytes
52 | protected override long FromBytes(byte[] buffer, int startIndex, int bytesToConvert)
53 | {
54 | long ret = 0;
55 | for (var i = 0; i < bytesToConvert; i++)
56 | ret = unchecked((ret << 8) | buffer[startIndex + bytesToConvert - 1 - i]);
57 | return ret;
58 | }
59 | }
60 | }
--------------------------------------------------------------------------------
/Utils/EntityState.cs:
--------------------------------------------------------------------------------
1 | using DarkRift;
2 |
3 | namespace Utils
4 | {
5 | public enum EntityState : byte
6 | {
7 | Idle,
8 | Moving,
9 | Casting,
10 | Dead,
11 |
12 | }
13 | }
--------------------------------------------------------------------------------
/Utils/Extensions/SerializationExtensions.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.IO;
3 | using System.Linq;
4 | using DarkRift;
5 | using Utils.Conversion;
6 | using Utils.IO;
7 |
8 | namespace Utils.Extensions
9 | {
10 | ///
11 | /// Contains functions to help easily serialize / deserialize some common types
12 | ///
13 | public static class SerializationExtensions
14 | {
15 | public static byte[] ToBytes(this Dictionary dictionary)
16 | {
17 | byte[] b;
18 | using (var ms = new MemoryStream())
19 | {
20 | using (var writer = new EndianBinaryWriter(EndianBitConverter.Big, ms))
21 | {
22 | dictionary.ToWriter(writer);
23 | }
24 |
25 | b = ms.ToArray();
26 | }
27 |
28 | return b;
29 | }
30 |
31 | public static void ToWriter(this Dictionary dictionary, EndianBinaryWriter writer)
32 | {
33 | if (dictionary == null)
34 | {
35 | writer.Write(0);
36 | return;
37 | }
38 |
39 | writer.Write(dictionary.Count);
40 |
41 | foreach (var item in dictionary)
42 | {
43 | writer.Write(item.Key);
44 | writer.Write(item.Value);
45 | }
46 | }
47 |
48 | public static Dictionary FromReader(this Dictionary dictionary,
49 | EndianBinaryReader reader)
50 | {
51 | var count = reader.ReadInt32();
52 |
53 | for (var i = 0; i < count; i++)
54 | {
55 | var key = reader.ReadString();
56 | var value = reader.ReadString();
57 | if (dictionary.ContainsKey(key))
58 | dictionary[key] = value;
59 | else
60 | dictionary.Add(key, value);
61 | }
62 |
63 | return dictionary;
64 | }
65 |
66 | public static Dictionary FromBytes(this Dictionary dictionary, byte[] data)
67 | {
68 | using (var ms = new MemoryStream(data))
69 | {
70 | using (var reader = new EndianBinaryReader(EndianBitConverter.Big, ms))
71 | {
72 | dictionary.FromReader(reader);
73 | }
74 | }
75 |
76 | return dictionary;
77 | }
78 | }
79 | }
--------------------------------------------------------------------------------
/Utils/Game/TundraVector3.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using DarkRift;
3 |
4 | namespace Utils.Game
5 | {
6 | public class TundraVector3 : IDarkRiftSerializable
7 | {
8 | public static TundraVector3 Zero => TundraVector3.Create(0f, 0f, 0f);
9 |
10 | public static TundraVector3 Create(float x, float y, float z)
11 | {
12 | return new TundraVector3 {X = x, Y = y, Z = z};
13 | }
14 |
15 | public float X { get; set; }
16 | public float Y { get; set; }
17 | public float Z { get; set; }
18 |
19 | public void Deserialize(DeserializeEvent e)
20 | {
21 | X = e.Reader.ReadSingle();
22 | Y = e.Reader.ReadSingle();
23 | Z = e.Reader.ReadSingle();
24 | }
25 |
26 | public void Serialize(SerializeEvent e)
27 | {
28 | e.Writer.Write(X);
29 | e.Writer.Write(Y);
30 | e.Writer.Write(Z);
31 | }
32 |
33 | public override string ToString()
34 | {
35 | return X + ", " + Y + ", " + Z;
36 | }
37 |
38 |
39 | public float Magnitude
40 | {
41 | get { return (float) Math.Sqrt(X * X + Y * Y + Z * Z); }
42 | }
43 |
44 | public static TundraVector3 operator /(TundraVector3 a, float d)
45 | {
46 | return Create(a.X / d, a.Y / d, a.Z / d);
47 | }
48 |
49 | public static TundraVector3 MoveTowards(TundraVector3 current, TundraVector3 target,
50 | float maxDistanceDelta)
51 | {
52 | var toVector = target - current;
53 | float dist = toVector.Magnitude;
54 | if (dist <= maxDistanceDelta || dist < float.Epsilon)
55 | return target;
56 | return current + (toVector / dist) * maxDistanceDelta;
57 | }
58 | public static float Distance(TundraVector3 a, TundraVector3 b)
59 | {
60 | return (a-b).Magnitude;
61 | }
62 |
63 | public static TundraVector3 operator -(TundraVector3 a, TundraVector3 b) { return Create(a.X - b.X, a.Y - b.Y, a.Z - b.Z); }
64 | public static TundraVector3 operator +(TundraVector3 a, TundraVector3 b) { return Create(a.X + b.X, a.Y + b.Y, a.Z + b.Z); }
65 | public static TundraVector3 operator *(TundraVector3 a, float d) { return Create(a.X * d, a.Y * d, a.Z * d); }
66 | }
67 | }
--------------------------------------------------------------------------------
/Utils/MessageTags.cs:
--------------------------------------------------------------------------------
1 | namespace Utils
2 | {
3 | public static class MessageTags
4 | {
5 | //Auth & Security
6 | public const ushort RequestAesKey = 1500;
7 | public const ushort RequestAesKeyResponse = 1501;
8 |
9 | public const ushort RequestPermissionLevel = 1550;
10 | public const ushort RequestPermissionLevelResponse = 1551;
11 |
12 | public const ushort LogIn = 2000;
13 | public const ushort LoginFailedResponse = 2001;
14 | public const ushort LoginSuccessResponse = 2002;
15 |
16 | public const ushort RegisterAccount = 2050;
17 | public const ushort RegisterAccountFailed = 2051;
18 | public const ushort RegisterAccountSuccess = 2052;
19 | public const ushort RequestPasswordResetCode = 2100;
20 |
21 | public const ushort ResetPassword = 2101;
22 | public const ushort ResetPasswordFailed = 2102;
23 | public const ushort ResetPasswordSuccess = 2103;
24 |
25 | public const ushort ConfirmEmail = 2150;
26 | public const ushort ConfirmEmailFailed = 2151;
27 | public const ushort ConfirmEmailSuccess = 2152;
28 | public const ushort RequestNewEmailConfirmationCode = 2153;
29 |
30 | //Spawners & Spawning
31 | public const ushort RegisterSpawner = 2200; //1.) Spawner.RegisterTo -> Master
32 | public const ushort RegisterSpawnerFailed = 2201;
33 | public const ushort RegisterSpawnerSuccess = 2202;
34 | public const ushort RequestSpawnFromClientToMaster = 2250; //2.) Client.RequestSpawnTo -> Master
35 | public const ushort RequestSpawnFromClientToMasterFailed = 2251;
36 | public const ushort RequestSpawnFromClientToMasterSuccess = 2252;
37 | public const ushort RequestSpawnFromMasterToSpawner = 2253; //3.) Master.CreateTaskFor -> Spawner
38 | public const ushort RequestSpawnFromMasterToSpawnerFailed = 2254;
39 | public const ushort RequestSpawnFromMasterToSpawnerSuccess = 2255;
40 | public const ushort RegisterSpawnedProcess = 2256; //4.) Spawn.RegisterProcessTo -> Master
41 | public const ushort RegisterSpawnedProcessSuccess = 2257;
42 | public const ushort RegisterSpawnedProcessFailed = 2258;
43 | public const ushort SpawnStatusChanged = 2259; //5.) Notification of Process-status
44 | public const ushort CompleteSpawnProcess = 2260; //6.) Spawn.NotifyCompleteTo -> Master
45 | public const ushort CompleteSpawnProcessFailed = 2261;
46 | public const ushort CompleteSpawnProcessSuccess = 2262;
47 | public const ushort GetFinalizationData = 2263; //7.) Client -> GetSpawnDataFromMaster
48 | public const ushort GetFinalizationDataFailed = 2264;
49 | public const ushort GetFinalizationDataSuccess = 2265;
50 | public const ushort KillSpawn = 2270;
51 | public const ushort NotifySpawnerKilledProcess = 2271;
52 |
53 | //Rooms
54 | public const ushort RegisterRoom = 2300;
55 | public const ushort RegisterRoomFailed = 2301;
56 | public const ushort RegisterRoomSuccess = 2302;
57 | public const ushort GetRoomAccess = 2303;
58 | public const ushort GetRoomAccessFailed = 2304;
59 | public const ushort GetRoomAccessSuccess = 2305;
60 | public const ushort ProvideRoomAccessCheck = 2350;
61 | public const ushort ProvideRoomAccessCheckFailed = 2351;
62 | public const ushort ProvideRoomAccessCheckSuccess = 2352;
63 | public const ushort ValidateRoomAccess = 2353;
64 | public const ushort ValidateRoomAccessFailed = 2354;
65 | public const ushort ValidateRoomAccessSuccess = 2355;
66 | public const ushort GetRooms = 2360; //Call from client
67 | public const ushort AccessRoom = 2370; //Call from client
68 |
69 | //Game-related
70 | public const ushort GetNetworkTime = 3000;
71 | //Entity-related
72 | public const ushort SpawnEntity = 3010;
73 | public const ushort DespawnPlayer = 3011;
74 | public const ushort NavigateTo = 3012;
75 | public const ushort ChangeState = 3013;
76 |
77 |
78 | //Debug
79 | public const ushort DebugPath = 60000;
80 | }
81 | }
--------------------------------------------------------------------------------
/Utils/Messages/NotificationMessage.cs:
--------------------------------------------------------------------------------
1 | using DarkRift;
2 |
3 | namespace Utils.Messages
4 | {
5 | public abstract class NotificationMessage : IDarkRiftSerializable
6 | {
7 | public virtual void Deserialize(DeserializeEvent e)
8 | {
9 | }
10 |
11 | public virtual void Serialize(SerializeEvent e)
12 | {
13 | }
14 | }
15 | }
--------------------------------------------------------------------------------
/Utils/Messages/Notifications/ProcessKilledMessage .cs:
--------------------------------------------------------------------------------
1 | using DarkRift;
2 |
3 | namespace Utils.Messages.Notifications
4 | {
5 | public class ProcessKilledMessage : NotificationMessage
6 | {
7 | public int SpawnerID;
8 | public int SpawnTaskID;
9 |
10 | public override void Deserialize(DeserializeEvent e)
11 | {
12 | base.Deserialize(e);
13 | SpawnerID = e.Reader.ReadInt32();
14 | SpawnTaskID = e.Reader.ReadInt32();
15 | }
16 |
17 | public override void Serialize(SerializeEvent e)
18 | {
19 | base.Serialize(e);
20 | e.Writer.Write(SpawnerID);
21 | e.Writer.Write(SpawnTaskID);
22 | }
23 | }
24 | }
--------------------------------------------------------------------------------
/Utils/Messages/Notifications/SpawnFinalizedMessage.cs:
--------------------------------------------------------------------------------
1 | using DarkRift;
2 |
3 | namespace Utils.Messages.Notifications
4 | {
5 | public class SpawnFinalizedMessage : IDarkRiftSerializable
6 | {
7 | public int SpawnTaskID;
8 | public int RoomID;
9 |
10 | public void Deserialize(DeserializeEvent e)
11 | {
12 | SpawnTaskID = e.Reader.ReadInt32();
13 | RoomID = e.Reader.ReadInt32();
14 | }
15 |
16 | public void Serialize(SerializeEvent e)
17 | {
18 | e.Writer.Write(SpawnTaskID);
19 | e.Writer.Write(RoomID);
20 | }
21 | }
22 | }
--------------------------------------------------------------------------------
/Utils/Messages/RequestMessage.cs:
--------------------------------------------------------------------------------
1 | using DarkRift;
2 |
3 | namespace Utils.Messages
4 | {
5 | public abstract class RequestMessage : IDarkRiftSerializable
6 | {
7 | public virtual void Deserialize(DeserializeEvent e)
8 | {
9 | }
10 |
11 | public virtual void Serialize(SerializeEvent e)
12 | {
13 | }
14 | }
15 | }
--------------------------------------------------------------------------------
/Utils/Messages/Requests/ConfirmEmailMessage.cs:
--------------------------------------------------------------------------------
1 | using System.Text;
2 | using DarkRift;
3 |
4 | namespace Utils.Messages.Requests
5 | {
6 | public class ConfirmEmailMessage : RequestFromUserMessage
7 | {
8 | public string Code;
9 |
10 | public override void Deserialize(DeserializeEvent e)
11 | {
12 | base.Deserialize(e);
13 | Code = e.Reader.ReadString(Encoding.Unicode);
14 | }
15 |
16 | public override void Serialize(SerializeEvent e)
17 | {
18 | base.Serialize(e);
19 | e.Writer.Write(Code, Encoding.Unicode);
20 | }
21 | }
22 | }
--------------------------------------------------------------------------------
/Utils/Messages/Requests/RegisterSpawnedProcessMessage.cs:
--------------------------------------------------------------------------------
1 | using DarkRift;
2 |
3 | namespace Utils.Messages.Requests
4 | {
5 | public class RegisterSpawnedProcessMessage : IDarkRiftSerializable
6 | {
7 | public string SpawnCode;
8 | public int SpawnTaskID;
9 |
10 | public void Deserialize(DeserializeEvent e)
11 | {
12 | SpawnTaskID = e.Reader.ReadInt32();
13 | SpawnCode = e.Reader.ReadString();
14 | }
15 |
16 | public void Serialize(SerializeEvent e)
17 | {
18 | e.Writer.Write(SpawnTaskID);
19 | e.Writer.Write(SpawnCode);
20 | }
21 | }
22 | }
--------------------------------------------------------------------------------
/Utils/Messages/Requests/RequestFromUserMessage.cs:
--------------------------------------------------------------------------------
1 | using System.Text;
2 | using DarkRift;
3 |
4 | namespace Utils.Messages.Requests
5 | {
6 | public class RequestFromUserMessage : RequestMessage
7 | {
8 | public string EMail;
9 |
10 | public override void Deserialize(DeserializeEvent e)
11 | {
12 | base.Deserialize(e);
13 | EMail = e.Reader.ReadString(Encoding.Unicode);
14 | }
15 |
16 | public override void Serialize(SerializeEvent e)
17 | {
18 | base.Serialize(e);
19 | e.Writer.Write(EMail, Encoding.Unicode);
20 | }
21 | }
22 | }
--------------------------------------------------------------------------------
/Utils/Messages/Requests/ResetPasswordMessage.cs:
--------------------------------------------------------------------------------
1 | using System.Text;
2 | using DarkRift;
3 |
4 | namespace Utils.Messages.Requests
5 | {
6 | public class ResetPasswordMessage : RequestMessage
7 | {
8 | public string Code;
9 | public string EMail;
10 | public string NewPassword;
11 |
12 | public override void Deserialize(DeserializeEvent e)
13 | {
14 | base.Deserialize(e);
15 | EMail = e.Reader.ReadString(Encoding.Unicode);
16 | Code = e.Reader.ReadString(Encoding.Unicode);
17 | NewPassword = e.Reader.ReadString(Encoding.Unicode);
18 | }
19 |
20 | public override void Serialize(SerializeEvent e)
21 | {
22 | base.Serialize(e);
23 | e.Writer.Write(EMail, Encoding.Unicode);
24 | e.Writer.Write(Code, Encoding.Unicode);
25 | e.Writer.Write(NewPassword, Encoding.Unicode);
26 | }
27 | }
28 | }
--------------------------------------------------------------------------------
/Utils/Messages/ResponseMessage.cs:
--------------------------------------------------------------------------------
1 | using DarkRift;
2 |
3 | namespace Utils.Messages
4 | {
5 | public abstract class ResponseMessage : IDarkRiftSerializable
6 | {
7 | public ResponseStatus Status;
8 |
9 | public virtual void Deserialize(DeserializeEvent e)
10 | {
11 | Status = (ResponseStatus) e.Reader.ReadInt16();
12 | }
13 |
14 | public virtual void Serialize(SerializeEvent e)
15 | {
16 | e.Writer.Write((short) Status);
17 | }
18 | }
19 | }
--------------------------------------------------------------------------------
/Utils/Messages/Responses/ClientSpawnSuccessMessage.cs:
--------------------------------------------------------------------------------
1 | using DarkRift;
2 |
3 | namespace Utils.Messages.Responses
4 | {
5 | public class ClientSpawnSuccessMessage : ResponseMessage
6 | {
7 | public int TaskID;
8 |
9 | public override void Deserialize(DeserializeEvent e)
10 | {
11 | base.Deserialize(e);
12 | TaskID = e.Reader.ReadInt32();
13 | }
14 |
15 | public override void Serialize(SerializeEvent e)
16 | {
17 | base.Serialize(e);
18 | e.Writer.Write(TaskID);
19 | }
20 | }
21 | }
--------------------------------------------------------------------------------
/Utils/Messages/Responses/FailedMessage.cs:
--------------------------------------------------------------------------------
1 | using System.Text;
2 | using DarkRift;
3 |
4 | namespace Utils.Messages.Responses
5 | {
6 | public class FailedMessage : ResponseMessage
7 | {
8 | public string Reason;
9 |
10 | public override void Deserialize(DeserializeEvent e)
11 | {
12 | base.Deserialize(e);
13 | Reason = e.Reader.ReadString(Encoding.Unicode);
14 | }
15 |
16 | public override void Serialize(SerializeEvent e)
17 | {
18 | base.Serialize(e);
19 | e.Writer.Write(Reason);
20 | }
21 | }
22 | }
--------------------------------------------------------------------------------
/Utils/Messages/Responses/LoginSuccessMessage.cs:
--------------------------------------------------------------------------------
1 | using DarkRift;
2 |
3 | namespace Utils.Messages.Responses
4 | {
5 | public class LoginSuccessMessage : ResponseMessage
6 | {
7 | public bool IsAdmin;
8 | public bool IsGuest;
9 |
10 | public override void Deserialize(DeserializeEvent e)
11 | {
12 | base.Deserialize(e);
13 | IsAdmin = e.Reader.ReadBoolean();
14 | IsGuest = e.Reader.ReadBoolean();
15 | }
16 |
17 | public override void Serialize(SerializeEvent e)
18 | {
19 | base.Serialize(e);
20 | e.Writer.Write(IsAdmin);
21 | e.Writer.Write(IsGuest);
22 | }
23 | }
24 | }
--------------------------------------------------------------------------------
/Utils/Messages/Responses/RegisterRoomSuccessMessage.cs:
--------------------------------------------------------------------------------
1 | using DarkRift;
2 |
3 | namespace Utils.Messages.Responses
4 | {
5 | public class RegisterRoomSuccessMessage : ResponseMessage
6 | {
7 | public int RoomID;
8 |
9 | public override void Deserialize(DeserializeEvent e)
10 | {
11 | base.Deserialize(e);
12 | RoomID = e.Reader.ReadInt32();
13 | }
14 |
15 | public override void Serialize(SerializeEvent e)
16 | {
17 | base.Serialize(e);
18 | e.Writer.Write(RoomID);
19 | }
20 | }
21 | }
--------------------------------------------------------------------------------
/Utils/Messages/Responses/RegisterSpawnerSuccessMessage.cs:
--------------------------------------------------------------------------------
1 | using DarkRift;
2 |
3 | namespace Utils.Messages.Responses
4 | {
5 | public class RegisterSpawnerSuccessMessage : ResponseMessage
6 | {
7 | public int SpawnerID;
8 |
9 | public override void Deserialize(DeserializeEvent e)
10 | {
11 | base.Deserialize(e);
12 | SpawnerID = e.Reader.ReadInt32();
13 | }
14 |
15 | public override void Serialize(SerializeEvent e)
16 | {
17 | base.Serialize(e);
18 | e.Writer.Write(SpawnerID);
19 | }
20 | }
21 | }
--------------------------------------------------------------------------------
/Utils/Messages/Responses/SpawnFromMasterToSpawnerFailedMessage.cs:
--------------------------------------------------------------------------------
1 | using DarkRift;
2 |
3 | namespace Utils.Messages.Responses
4 | {
5 | public class SpawnFromMasterToSpawnerFailedMessage : FailedMessage
6 | {
7 | public int SpawnTaskID;
8 |
9 | public override void Serialize(SerializeEvent e)
10 | {
11 | base.Serialize(e);
12 | e.Writer.Write(SpawnTaskID);
13 | }
14 |
15 | public override void Deserialize(DeserializeEvent e)
16 | {
17 | base.Deserialize(e);
18 | SpawnTaskID = e.Reader.ReadInt32();
19 | }
20 | }
21 | }
--------------------------------------------------------------------------------
/Utils/Messages/Responses/SpawnFromMasterToSpawnerSuccessMessage.cs:
--------------------------------------------------------------------------------
1 | using System.Text;
2 | using DarkRift;
3 |
4 | namespace Utils.Messages.Responses
5 | {
6 | public class SpawnFromMasterToSpawnerSuccessMessage : ResponseMessage
7 | {
8 | public string Arguments;
9 | public int ProcessID;
10 | public int SpawnTaskID;
11 |
12 | public override void Serialize(SerializeEvent e)
13 | {
14 | base.Serialize(e);
15 | e.Writer.Write(SpawnTaskID);
16 | e.Writer.Write(ProcessID);
17 | e.Writer.Write(Arguments, Encoding.Unicode);
18 | }
19 |
20 | public override void Deserialize(DeserializeEvent e)
21 | {
22 | base.Deserialize(e);
23 | SpawnTaskID = e.Reader.ReadInt32();
24 | ProcessID = e.Reader.ReadInt32();
25 | Arguments = e.Reader.ReadString(Encoding.Unicode);
26 | }
27 | }
28 | }
--------------------------------------------------------------------------------
/Utils/NetworkEntity.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Text;
3 | using DarkRift;
4 | using Utils.Game;
5 |
6 | namespace Utils
7 | {
8 | public class NetworkEntity : IDarkRiftSerializable
9 | {
10 | public uint ID;
11 | public uint TargetID;
12 | public string Name = "Unknown";
13 |
14 | public EntityState State = EntityState.Idle;
15 |
16 | public TundraVector3 Position;
17 |
18 | public int Health = 100;
19 |
20 | public float Speed = 5f;
21 |
22 |
23 | public void Deserialize(DeserializeEvent e)
24 | {
25 | ID = e.Reader.ReadUInt32();
26 | TargetID = e.Reader.ReadUInt32();
27 | Name = e.Reader.ReadString(Encoding.Unicode);
28 | State = (EntityState)e.Reader.ReadByte();
29 | Position = e.Reader.ReadSerializable();
30 | Health = e.Reader.ReadInt32();
31 |
32 |
33 | }
34 |
35 | public void Serialize(SerializeEvent e)
36 | {
37 | e.Writer.Write(ID);
38 | e.Writer.Write(TargetID);
39 | e.Writer.Write(Name, Encoding.Unicode);
40 | e.Writer.Write((byte)State);
41 | e.Writer.Write(Position);
42 | e.Writer.Write(Health);
43 | }
44 | }
45 | }
--------------------------------------------------------------------------------
/Utils/Packets/AckNavigateToPacket.cs:
--------------------------------------------------------------------------------
1 | using DarkRift;
2 | using Utils.Game;
3 |
4 | namespace Utils.Packets
5 | {
6 | public class AckNavigateToPacket : IDarkRiftSerializable
7 | {
8 | public uint EntityID;
9 | //TODO: Calculate same navmesh on all clients & use a shared Agent for pathfinding => only send Destination instead of complete path
10 | public SmoothPath Path;
11 | public float Speed;
12 | public float StoppingDistance;
13 |
14 | public void Deserialize(DeserializeEvent e)
15 | {
16 | EntityID = e.Reader.ReadUInt32();
17 | Path = e.Reader.ReadSerializable();
18 | Speed = e.Reader.ReadSingle();
19 | StoppingDistance = e.Reader.ReadSingle();
20 | }
21 |
22 | public void Serialize(SerializeEvent e)
23 | {
24 | e.Writer.Write(EntityID);
25 | e.Writer.Write(Path);
26 | e.Writer.Write(Speed);
27 | e.Writer.Write(StoppingDistance);
28 | }
29 |
30 | public override string ToString()
31 | {
32 | return $"Entity: {EntityID} - {Path.PointsCount} Points with Speed {Speed} (StoppingDistance: {StoppingDistance})";
33 | }
34 | }
35 | }
--------------------------------------------------------------------------------
/Utils/Packets/BytePacket.cs:
--------------------------------------------------------------------------------
1 | using DarkRift;
2 |
3 | namespace Utils.Packets
4 | {
5 | public class BytePacket : IDarkRiftSerializable
6 | {
7 | public byte Data;
8 | public void Deserialize(DeserializeEvent e)
9 | {
10 | Data = e.Reader.ReadByte();
11 | }
12 |
13 | public void Serialize(SerializeEvent e)
14 | {
15 | e.Writer.Write(Data);
16 | }
17 | }
18 | }
--------------------------------------------------------------------------------
/Utils/Packets/BytesPacket.cs:
--------------------------------------------------------------------------------
1 | using DarkRift;
2 |
3 | namespace Utils.Packets
4 | {
5 | public class BytesPacket : IDarkRiftSerializable
6 | {
7 | public byte[] Data;
8 | public void Deserialize(DeserializeEvent e)
9 | {
10 | Data = e.Reader.ReadBytes();
11 | }
12 |
13 | public void Serialize(SerializeEvent e)
14 | {
15 | e.Writer.Write(Data);
16 | }
17 | }
18 | }
--------------------------------------------------------------------------------
/Utils/Packets/ChangStatePacket.cs:
--------------------------------------------------------------------------------
1 | using DarkRift;
2 | using Utils.Game;
3 |
4 | namespace Utils.Packets
5 | {
6 | public class ChangStatePacket : IDarkRiftSerializable
7 | {
8 | public uint EntityID;
9 | public EntityState State;
10 |
11 | public void Deserialize(DeserializeEvent e)
12 | {
13 | EntityID = e.Reader.ReadUInt32();
14 | State = (EntityState) e.Reader.ReadByte();
15 | }
16 |
17 | public void Serialize(SerializeEvent e)
18 | {
19 | e.Writer.Write(EntityID);
20 | e.Writer.Write((byte) State);
21 | }
22 | }
23 | }
--------------------------------------------------------------------------------
/Utils/Packets/EntityPacket.cs:
--------------------------------------------------------------------------------
1 | using DarkRift;
2 | using Utils.Game;
3 |
4 | namespace Utils.Packets
5 | {
6 | public class EntityPacket : IDarkRiftSerializable
7 | {
8 | public NetworkEntity NetworkEntity;
9 | public bool HasAuthority;
10 |
11 | public void Deserialize(DeserializeEvent e)
12 | {
13 | NetworkEntity = e.Reader.ReadSerializable();
14 | HasAuthority = e.Reader.ReadBoolean();
15 | }
16 |
17 | public void Serialize(SerializeEvent e)
18 | {
19 | e.Writer.Write(NetworkEntity);
20 | e.Writer.Write(HasAuthority);
21 | }
22 | }
23 | }
--------------------------------------------------------------------------------
/Utils/Packets/FloatPacket.cs:
--------------------------------------------------------------------------------
1 | using DarkRift;
2 |
3 | namespace Utils.Packets
4 | {
5 | public class FloatPacket : IDarkRiftSerializable
6 | {
7 | public float Data;
8 |
9 | public void Deserialize(DeserializeEvent e)
10 | {
11 | Data = e.Reader.ReadSingle();
12 | }
13 |
14 | public void Serialize(SerializeEvent e)
15 | {
16 | e.Writer.Write(Data);
17 | }
18 | }
19 | }
--------------------------------------------------------------------------------
/Utils/Packets/GameInfoPacket.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using DarkRift;
3 |
4 | namespace Utils.Packets
5 | {
6 | public class GameInfoPacket : IDarkRiftSerializable
7 | {
8 | public int Count;
9 | public List Games;
10 |
11 | public void Deserialize(DeserializeEvent e)
12 | {
13 | Count = e.Reader.ReadInt32();
14 | Games = new List();
15 | for (var i = 0; i < Count; i++)
16 | {
17 | Games.Add(e.Reader.ReadSerializable());
18 | }
19 | }
20 |
21 | public void Serialize(SerializeEvent e)
22 | {
23 | e.Writer.Write(Games.Count);
24 | foreach (var game in Games)
25 | {
26 | e.Writer.Write(game);
27 | }
28 | }
29 | }
30 |
31 | public class GameInfo : IDarkRiftSerializable
32 | {
33 | public int ID;
34 | public string Name = "";
35 | public int MaxPlayers;
36 | public int OnlinePlayers;
37 |
38 | public override string ToString()
39 | {
40 | return string.Format("[GameInfo: id: {0}, address: {1}, players: {2}/{3}, type: {4}]",
41 | ID, OnlinePlayers, MaxPlayers);
42 | }
43 |
44 | public void Deserialize(DeserializeEvent e)
45 | {
46 | ID = e.Reader.ReadInt32();
47 | Name = e.Reader.ReadString();
48 | MaxPlayers = e.Reader.ReadInt32();
49 | OnlinePlayers = e.Reader.ReadInt32();
50 | }
51 |
52 | public void Serialize(SerializeEvent e)
53 | {
54 | e.Writer.Write(ID);
55 | e.Writer.Write(Name);
56 | e.Writer.Write(MaxPlayers);
57 | e.Writer.Write(OnlinePlayers);
58 | }
59 | }
60 | }
--------------------------------------------------------------------------------
/Utils/Packets/IntPacket.cs:
--------------------------------------------------------------------------------
1 | using DarkRift;
2 |
3 | namespace Utils.Packets
4 | {
5 | public class IntPacket : IDarkRiftSerializable
6 | {
7 | public int Data;
8 |
9 | public void Deserialize(DeserializeEvent e)
10 | {
11 | Data = e.Reader.ReadInt32();
12 | }
13 |
14 | public void Serialize(SerializeEvent e)
15 | {
16 | e.Writer.Write(Data);
17 | }
18 | }
19 | }
--------------------------------------------------------------------------------
/Utils/Packets/KillSpawnedProcessPacket.cs:
--------------------------------------------------------------------------------
1 | using DarkRift;
2 |
3 | namespace Utils.Packets
4 | {
5 | public class KillSpawnedProcessPacket : IDarkRiftSerializable
6 | {
7 | public int SpawnerId;
8 | public int SpawnId;
9 |
10 | public void Deserialize(DeserializeEvent e)
11 | {
12 | SpawnerId = e.Reader.ReadInt32();
13 | SpawnId = e.Reader.ReadInt32();
14 | }
15 |
16 | public void Serialize(SerializeEvent e)
17 | {
18 | e.Writer.Write(SpawnerId);
19 | e.Writer.Write(SpawnId);
20 | }
21 | }
22 | }
--------------------------------------------------------------------------------
/Utils/Packets/NavigateToPacket.cs:
--------------------------------------------------------------------------------
1 | using DarkRift;
2 | using Utils.Game;
3 |
4 | namespace Utils.Packets
5 | {
6 | public class NavigateToPacket : IDarkRiftSerializable
7 | {
8 | public TundraVector3 Destination;
9 |
10 | public void Deserialize(DeserializeEvent e)
11 | {
12 | Destination = e.Reader.ReadSerializable();
13 | }
14 |
15 | public void Serialize(SerializeEvent e)
16 | {
17 | e.Writer.Write(Destination);
18 | }
19 | }
20 | }
--------------------------------------------------------------------------------
/Utils/Packets/PlayerLeftRoomPacket.cs:
--------------------------------------------------------------------------------
1 | using DarkRift;
2 |
3 | namespace Utils.Packets
4 | {
5 | public class PlayerLeftRoomPacket : IDarkRiftSerializable
6 | {
7 | public int PeerId;
8 | public int RoomId;
9 |
10 | public void Deserialize(DeserializeEvent e)
11 | {
12 | PeerId = e.Reader.ReadInt32();
13 | RoomId = e.Reader.ReadInt32();
14 | }
15 |
16 | public void Serialize(SerializeEvent e)
17 | {
18 | e.Writer.Write(PeerId);
19 | e.Writer.Write(RoomId);
20 | }
21 | }
22 | }
--------------------------------------------------------------------------------
/Utils/Packets/PositionPacket.cs:
--------------------------------------------------------------------------------
1 | using DarkRift;
2 | using Utils.Game;
3 |
4 | namespace Utils.Packets
5 | {
6 | public class PositionPacket : IDarkRiftSerializable
7 | {
8 | public TundraVector3 Vector3 { get; set; }
9 |
10 | public void Deserialize(DeserializeEvent e)
11 | {
12 | throw new System.NotImplementedException();
13 | }
14 |
15 | public void Serialize(SerializeEvent e)
16 | {
17 | throw new System.NotImplementedException();
18 | }
19 | }
20 | }
--------------------------------------------------------------------------------
/Utils/Packets/RoomAccessPacket.cs:
--------------------------------------------------------------------------------
1 | using DarkRift;
2 |
3 | namespace Utils.Packets
4 | {
5 | public class RoomAccessPacket : IDarkRiftSerializable
6 | {
7 | public int ClientID;
8 | public int RoomID;
9 | public string RoomIp;
10 | public int RoomPort;
11 | public string RoomName = "";
12 | public string Token;
13 |
14 | public void Deserialize(DeserializeEvent e)
15 | {
16 | ClientID = e.Reader.ReadInt32();
17 | Token = e.Reader.ReadString();
18 | RoomIp = e.Reader.ReadString();
19 | RoomPort = e.Reader.ReadInt32();
20 | RoomID = e.Reader.ReadInt32();
21 | RoomName = e.Reader.ReadString();
22 | }
23 |
24 | public void Serialize(SerializeEvent e)
25 | {
26 | e.Writer.Write(ClientID);
27 | e.Writer.Write(Token);
28 | e.Writer.Write(RoomIp);
29 | e.Writer.Write(RoomPort);
30 | e.Writer.Write(RoomID);
31 | e.Writer.Write(RoomName);
32 | }
33 |
34 | public override string ToString()
35 | {
36 | return $"[RoomAccessPacket| PublicAddress: {RoomIp + ":" + RoomPort}, RoomId: {RoomID}, Token: {Token}]";
37 | }
38 | }
39 | }
--------------------------------------------------------------------------------
/Utils/Packets/RoomAccessProvideCheckPacket.cs:
--------------------------------------------------------------------------------
1 | using DarkRift;
2 |
3 | namespace Utils.Packets
4 | {
5 | public class RoomAccessProvideCheckPacket : IDarkRiftSerializable
6 | {
7 | public int ClientID;
8 | public int RoomID;
9 |
10 | public void Deserialize(DeserializeEvent e)
11 | {
12 | ClientID = e.Reader.ReadInt32();
13 | RoomID = e.Reader.ReadInt32();
14 | }
15 |
16 | public void Serialize(SerializeEvent e)
17 | {
18 | e.Writer.Write(ClientID);
19 | e.Writer.Write(RoomID);
20 | }
21 | }
22 | }
--------------------------------------------------------------------------------
/Utils/Packets/RoomAccessRequestPacket.cs:
--------------------------------------------------------------------------------
1 | using DarkRift;
2 |
3 | namespace Utils.Packets
4 | {
5 | public class RoomAccessRequestPacket : IDarkRiftSerializable
6 | {
7 | public string Password = "";
8 | public int RoomId;
9 |
10 | public void Deserialize(DeserializeEvent e)
11 | {
12 | RoomId = e.Reader.ReadInt32();
13 | Password = e.Reader.ReadString();
14 | }
15 |
16 | public void Serialize(SerializeEvent e)
17 | {
18 | e.Writer.Write(RoomId);
19 | e.Writer.Write(Password);
20 | }
21 | }
22 | }
--------------------------------------------------------------------------------
/Utils/Packets/RoomAccessValidatePacket.cs:
--------------------------------------------------------------------------------
1 | using DarkRift;
2 |
3 | namespace Utils.Packets
4 | {
5 | public class RoomAccessValidatePacket : IDarkRiftSerializable
6 | {
7 | public int RoomID;
8 | public string Token;
9 | public int ClientID;
10 |
11 |
12 | public void Deserialize(DeserializeEvent e)
13 | {
14 | Token = e.Reader.ReadString();
15 | RoomID = e.Reader.ReadInt32();
16 | ClientID = e.Reader.ReadInt32();
17 | }
18 |
19 | public void Serialize(SerializeEvent e)
20 | {
21 | e.Writer.Write(Token);
22 | e.Writer.Write(RoomID);
23 | e.Writer.Write(ClientID);
24 | }
25 | }
26 | }
--------------------------------------------------------------------------------
/Utils/Packets/RoomAccessValidatedPacket.cs:
--------------------------------------------------------------------------------
1 | using DarkRift;
2 |
3 | namespace Utils.Packets
4 | {
5 | public class RoomAccessValidatedPacket : IDarkRiftSerializable
6 | {
7 | public int MasterClientID;
8 | public int ClientID;
9 |
10 |
11 | public void Deserialize(DeserializeEvent e)
12 | {
13 | MasterClientID = e.Reader.ReadInt32();
14 | ClientID = e.Reader.ReadInt32();
15 | }
16 |
17 | public void Serialize(SerializeEvent e)
18 | {
19 | e.Writer.Write(MasterClientID);
20 | e.Writer.Write(ClientID);
21 | }
22 | }
23 | }
--------------------------------------------------------------------------------
/Utils/Packets/SaveRoomOptionsPacket.cs:
--------------------------------------------------------------------------------
1 | using DarkRift;
2 |
3 | namespace Utils.Packets
4 | {
5 | public class SaveRoomOptionsPacket : IDarkRiftSerializable
6 | {
7 | public RoomOptions Options;
8 | public int RoomId;
9 |
10 | public void Deserialize(DeserializeEvent e)
11 | {
12 | RoomId = e.Reader.ReadInt32();
13 | Options = e.Reader.ReadSerializable();
14 | }
15 |
16 | public void Serialize(SerializeEvent e)
17 | {
18 | e.Writer.Write(RoomId);
19 | e.Writer.Write(Options);
20 | }
21 | }
22 | }
--------------------------------------------------------------------------------
/Utils/Packets/SpawnRequestPacket.cs:
--------------------------------------------------------------------------------
1 | using DarkRift;
2 |
3 | namespace Utils.Packets
4 | {
5 | public class SpawnRequestPacket : IDarkRiftSerializable
6 | {
7 | public string SpawnCode;
8 | public int SpawnerId;
9 | public int SpawnTaskID;
10 | public RoomOptions Options;
11 |
12 | public void Deserialize(DeserializeEvent e)
13 | {
14 | SpawnerId = e.Reader.ReadInt32();
15 | SpawnTaskID = e.Reader.ReadInt32();
16 | SpawnCode = e.Reader.ReadString();
17 | Options = e.Reader.ReadSerializable();
18 | }
19 |
20 | public void Serialize(SerializeEvent e)
21 | {
22 | e.Writer.Write(SpawnerId);
23 | e.Writer.Write(SpawnTaskID);
24 | e.Writer.Write(SpawnCode);
25 | e.Writer.Write(Options);
26 | }
27 | }
28 | }
--------------------------------------------------------------------------------
/Utils/Packets/SpawnStatusPacket.cs:
--------------------------------------------------------------------------------
1 | using DarkRift;
2 |
3 | namespace Utils.Packets
4 | {
5 | public class SpawnStatusPacket : IDarkRiftSerializable
6 | {
7 | public int SpawnTaskID;
8 | public SpawnStatus Status;
9 |
10 | public void Deserialize(DeserializeEvent e)
11 | {
12 | SpawnTaskID = e.Reader.ReadInt32();
13 | Status = (SpawnStatus) e.Reader.ReadInt32();
14 | }
15 |
16 | public void Serialize(SerializeEvent e)
17 | {
18 | e.Writer.Write(SpawnTaskID);
19 | e.Writer.Write((int) Status);
20 | }
21 | }
22 | }
--------------------------------------------------------------------------------
/Utils/Packets/StringPacket.cs:
--------------------------------------------------------------------------------
1 | using System.Text;
2 | using DarkRift;
3 |
4 | namespace Utils.Packets
5 | {
6 | public class StringPacket : IDarkRiftSerializable
7 | {
8 | public string Data;
9 |
10 | public void Deserialize(DeserializeEvent e)
11 | {
12 | Data = e.Reader.ReadString(Encoding.Unicode);
13 | }
14 |
15 | public void Serialize(SerializeEvent e)
16 | {
17 | e.Writer.Write(Data, Encoding.Unicode);
18 | }
19 | }
20 | }
--------------------------------------------------------------------------------
/Utils/Packets/UsernameAndPeerIdPacket.cs:
--------------------------------------------------------------------------------
1 | using DarkRift;
2 |
3 | namespace Utils.Packets
4 | {
5 | public class UsernameAndPeerIdPacket : IDarkRiftSerializable
6 | {
7 | public int ClientID;
8 | public string Username = "";
9 |
10 | public void Deserialize(DeserializeEvent e)
11 | {
12 | Username = e.Reader.ReadString();
13 | ClientID = e.Reader.ReadInt32();
14 | }
15 |
16 | public void Serialize(SerializeEvent e)
17 | {
18 | e.Writer.Write(Username);
19 | e.Writer.Write(ClientID);
20 | }
21 |
22 | public override string ToString()
23 | {
24 | return string.Format("[Username: {0}, Peer ID: {1}]", Username, ClientID);
25 | }
26 | }
27 | }
--------------------------------------------------------------------------------
/Utils/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.InteropServices;
3 |
4 | // General Information about an assembly is controlled through the following
5 | // set of attributes. Change these attribute values to modify the information
6 | // associated with an assembly.
7 | [assembly: AssemblyTitle("TundraNetServerPluginData")]
8 | [assembly: AssemblyDescription("")]
9 | [assembly: AssemblyConfiguration("")]
10 | [assembly: AssemblyCompany("")]
11 | [assembly: AssemblyProduct("TundraNetServerPluginData")]
12 | [assembly: AssemblyCopyright("Copyright © 2018")]
13 | [assembly: AssemblyTrademark("")]
14 | [assembly: AssemblyCulture("")]
15 |
16 | // Setting ComVisible to false makes the types in this assembly not visible
17 | // to COM components. If you need to access a type in this assembly from
18 | // COM, set the ComVisible attribute to true on that type.
19 | [assembly: ComVisible(false)]
20 |
21 | // The following GUID is for the ID of the typelib if this project is exposed to COM
22 | [assembly: Guid("73957a5c-7298-4bd7-97a7-6e572b50d155")]
23 |
24 | // Version information for an assembly consists of the following four values:
25 | //
26 | // Major Version
27 | // Minor Version
28 | // Build Number
29 | // Revision
30 | //
31 | // You can specify all the values or you can default the Build and Revision Numbers
32 | // by using the '*' as shown below:
33 | // [assembly: AssemblyVersion("1.0.*")]
34 | [assembly: AssemblyVersion("1.0.0.0")]
35 | [assembly: AssemblyFileVersion("1.0.0.0")]
--------------------------------------------------------------------------------
/Utils/ResponseStatus.cs:
--------------------------------------------------------------------------------
1 | namespace Utils
2 | {
3 | public enum ResponseStatus
4 | {
5 | Default = 0,
6 | Success = 1,
7 | Timeout = 2,
8 | Error = 3,
9 | Unauthorized = 4,
10 | Invalid = 5,
11 | Failed = 6,
12 | NotConnected = 7,
13 | NotHandled = 8,
14 | Unconfirmed = 9
15 | }
16 | }
--------------------------------------------------------------------------------
/Utils/RoomOptions.cs:
--------------------------------------------------------------------------------
1 | using DarkRift;
2 |
3 | namespace Utils
4 | {
5 | ///
6 | /// List of options, which are sent to master server during registration
7 | ///
8 | public class RoomOptions : IDarkRiftSerializable
9 | {
10 | public bool IsPublic;
11 | public int MaxPlayers;
12 | public string WorldName;
13 | public string RoomName;
14 | public string Region;
15 |
16 |
17 | public void Deserialize(DeserializeEvent e)
18 | {
19 | WorldName = e.Reader.ReadString();
20 | RoomName = e.Reader.ReadString();
21 | IsPublic = e.Reader.ReadBoolean();
22 | MaxPlayers = e.Reader.ReadInt32();
23 | Region = e.Reader.ReadString();
24 | }
25 |
26 | public void Serialize(SerializeEvent e)
27 | {
28 | e.Writer.Write(WorldName);
29 | e.Writer.Write(RoomName);
30 | e.Writer.Write(IsPublic);
31 | e.Writer.Write(MaxPlayers);
32 | e.Writer.Write(Region);
33 | }
34 | }
35 | }
--------------------------------------------------------------------------------
/Utils/Security.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using System.Security.Cryptography;
4 | using System.Text;
5 | using Utils.Conversion;
6 | using Utils.IO;
7 |
8 | namespace Utils
9 | {
10 | public class Security
11 | {
12 | private static readonly byte[] Salt = Encoding.ASCII.GetBytes("o6806642kbM7c5");
13 |
14 | //Anti time-attacks
15 | public static bool SlowEquals(byte[] a, byte[] b)
16 | {
17 | var diff = (uint) a.Length ^ (uint) b.Length;
18 | for (var i = 0; i < a.Length && i < b.Length; i++)
19 | diff |= (uint) (a[i] ^ b[i]);
20 | return diff == 0;
21 | }
22 |
23 | public static bool ValidatePassword(string password, string correctHash)
24 | {
25 | // Extract the parameters from the hash
26 | char[] delimiter = {':'};
27 | var split = correctHash.Split(delimiter);
28 | var iterations = int.Parse(split[ITERATION_INDEX]);
29 | var salt = Convert.FromBase64String(split[SALT_INDEX]);
30 | var hash = Convert.FromBase64String(split[PBKDF2_INDEX]);
31 |
32 | var testHash = PBKDF2(password, salt, iterations, hash.Length);
33 | return SlowEquals(hash, testHash);
34 | }
35 |
36 | public static string CreateHash(string password)
37 | {
38 | // Generate a random salt
39 | var csprng = new RNGCryptoServiceProvider();
40 | var salt = new byte[SALT_BYTE_SIZE];
41 | csprng.GetBytes(salt);
42 |
43 | // Hash the password and encode the parameters
44 | var hash = PBKDF2(password, salt, PBKDF2_ITERATIONS, HASH_BYTE_SIZE);
45 | return PBKDF2_ITERATIONS + ":" +
46 | Convert.ToBase64String(salt) + ":" +
47 | Convert.ToBase64String(hash);
48 | }
49 |
50 | private static byte[] PBKDF2(string password, byte[] salt, int iterations, int outputBytes)
51 | {
52 | var pbkdf2 = new Rfc2898DeriveBytes(password, salt);
53 | pbkdf2.IterationCount = iterations;
54 | return pbkdf2.GetBytes(outputBytes);
55 | }
56 |
57 | public static byte[] DecryptAES(byte[] encryptedData, string sharedSecret)
58 | {
59 | using (var aesAlg = new RijndaelManaged())
60 | {
61 | // generate the key from the shared secret and the salt
62 | var key = new Rfc2898DeriveBytes(sharedSecret, Salt);
63 |
64 | using (var msDecrypt = new MemoryStream(encryptedData))
65 | {
66 | // Get the key
67 | aesAlg.Key = key.GetBytes(aesAlg.KeySize / 8);
68 | // Get the initialization vector from the encrypted stream
69 | aesAlg.IV = ReadByteArray(msDecrypt);
70 | // Create a decrytor to perform the stream transform.
71 | var decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
72 | using (var csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
73 | {
74 | using (var reader = new EndianBinaryReader(EndianBitConverter.Big, csDecrypt))
75 | {
76 | return reader.ReadBytes(reader.ReadInt32());
77 | }
78 | }
79 | }
80 | }
81 | }
82 |
83 | public static byte[] EncryptAES(byte[] rawData, string sharedSecret)
84 | {
85 | using (var aesAlg = new RijndaelManaged())
86 | {
87 | // generate the key from the shared secret and the salt
88 | var key = new Rfc2898DeriveBytes(sharedSecret, Salt);
89 |
90 | // Create a RijndaelManaged object
91 | aesAlg.Key = key.GetBytes(aesAlg.KeySize / 8);
92 |
93 | // Create a decryptor to perform the stream transform.
94 | var encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
95 |
96 | // Create the streams used for encryption.
97 | using (var msEncrypt = new MemoryStream())
98 | {
99 | // prepend the IV
100 | msEncrypt.Write(BitConverter.GetBytes(aesAlg.IV.Length), 0, sizeof(int));
101 | msEncrypt.Write(aesAlg.IV, 0, aesAlg.IV.Length);
102 | using (var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
103 | {
104 | using (var writer = new EndianBinaryWriter(EndianBitConverter.Big, csEncrypt))
105 | {
106 | //Write all data to the stream.
107 | writer.Write(rawData.Length);
108 | writer.Write(rawData);
109 | }
110 | }
111 |
112 | return msEncrypt.ToArray();
113 | }
114 | }
115 | }
116 |
117 | private static byte[] ReadByteArray(Stream s)
118 | {
119 | var rawLength = new byte[sizeof(int)];
120 | if (s.Read(rawLength, 0, rawLength.Length) != rawLength.Length)
121 | throw new SystemException("Stream did not contain properly formatted byte array");
122 |
123 | var buffer = new byte[BitConverter.ToInt32(rawLength, 0)];
124 | if (s.Read(buffer, 0, buffer.Length) != buffer.Length)
125 | throw new SystemException("Did not read byte array properly");
126 |
127 | return buffer;
128 | }
129 |
130 | public static string CreateRandomString(int length)
131 | {
132 | if (length < 0) throw new ArgumentOutOfRangeException("length", "length cannot be less than zero.");
133 |
134 | return Guid.NewGuid().ToString().Substring(0, length);
135 | }
136 |
137 | #region Password hashing
138 |
139 | // The following constants may be changed without breaking existing hashes.
140 | private const int SALT_BYTE_SIZE = 24;
141 | private const int HASH_BYTE_SIZE = 24;
142 | private const int PBKDF2_ITERATIONS = 1000;
143 |
144 | private const int ITERATION_INDEX = 0;
145 | private const int SALT_INDEX = 1;
146 | private const int PBKDF2_INDEX = 2;
147 |
148 | #endregion
149 | }
150 | }
--------------------------------------------------------------------------------
/Utils/SmoothPath.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 | using System.Collections.Generic;
3 | using DarkRift;
4 | using Utils.Game;
5 |
6 | namespace Utils
7 | {
8 | public class SmoothPath : IDarkRiftSerializable, IEnumerable
9 | {
10 | public const int MAX_POLYS = 256;
11 | public const int MAX_SMOOTH = 2048;
12 |
13 | public int PointsCount;
14 | public readonly List Points = new List();
15 | public void Deserialize(DeserializeEvent e)
16 | {
17 | PointsCount = e.Reader.ReadInt32();
18 | for (int i = 0; i < PointsCount; ++i)
19 | {
20 | Points.Add(e.Reader.ReadSerializable());
21 | }
22 | }
23 |
24 | public void Serialize(SerializeEvent e)
25 | {
26 | e.Writer.Write(Points.Count);
27 | foreach (var point in Points)
28 | {
29 | e.Writer.Write(point);
30 | }
31 | }
32 |
33 | public IEnumerator GetEnumerator()
34 | {
35 | return Points.GetEnumerator();
36 | }
37 |
38 | IEnumerator IEnumerable.GetEnumerator()
39 | {
40 | return GetEnumerator();
41 | }
42 | }
43 | }
--------------------------------------------------------------------------------
/Utils/SpawnStatus.cs:
--------------------------------------------------------------------------------
1 | namespace Utils
2 | {
3 | public enum SpawnStatus
4 | {
5 | Killed = -3,
6 | Aborted = -2,
7 | Aborting = -1,
8 |
9 | None,
10 | InQueue,
11 | StartingProcess,
12 | WaitingForProcess,
13 | ProcessRegistered,
14 | Finalized
15 | }
16 | }
--------------------------------------------------------------------------------
/Utils/SpawnerOptions.cs:
--------------------------------------------------------------------------------
1 | using DarkRift;
2 |
3 | namespace Utils
4 | {
5 | public class SpawnerOptions : IDarkRiftSerializable
6 | {
7 | public string MachineIp = "xxx.xxx.xxx.xxx";
8 |
9 | public int MaxProcesses;
10 |
11 | public string Region = "International";
12 |
13 | public void Deserialize(DeserializeEvent e)
14 | {
15 | MachineIp = e.Reader.ReadString();
16 | MaxProcesses = e.Reader.ReadInt32();
17 | Region = e.Reader.ReadString();
18 | }
19 |
20 | public void Serialize(SerializeEvent e)
21 | {
22 | e.Writer.Write(MachineIp);
23 | e.Writer.Write(MaxProcesses);
24 | e.Writer.Write(Region);
25 | }
26 |
27 | public override string ToString()
28 | {
29 | return $"PublicIp: {MachineIp}, MaxProcesses: {MaxProcesses}, Region: {Region}";
30 | }
31 | }
32 | }
--------------------------------------------------------------------------------
/Utils/Utils.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {73957A5C-7298-4BD7-97A7-6E572B50D155}
8 | Library
9 | Properties
10 | Utils
11 | Utils
12 | v3.5
13 | 512
14 |
15 |
16 | true
17 | full
18 | false
19 | bin\Debug\
20 | DEBUG;TRACE
21 | prompt
22 | 4
23 |
24 |
25 | pdbonly
26 | true
27 | bin\Release\
28 | TRACE
29 | prompt
30 | 4
31 |
32 |
33 | OnOutputUpdated
34 |
35 |
36 |
37 | ..\Deploy\Lib\DarkRift.dll
38 |
39 |
40 |
41 |
42 | ..\packages\System.Threading.Tasks.Unofficial.3.1\lib\net35\System.Threading.Tasks.NET35.dll
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 | xcopy /d /y $(TargetDir)$(TargetName).dll E:\UnityProjects\TundraClient\Assets\Plugins\DarkRift
116 | xcopy /d /y $(TargetDir)$(TargetName).pdb E:\UnityProjects\TundraClient\Assets\Plugins\DarkRift
117 |
118 |
119 |
120 |
--------------------------------------------------------------------------------
/Utils/WorldOptions.cs:
--------------------------------------------------------------------------------
1 | using DarkRift;
2 |
3 | namespace Utils
4 | {
5 | ///
6 | /// List of options, which are sent to master server during registration
7 | ///
8 | public class WorldOptions : IDarkRiftSerializable
9 | {
10 | public bool IsPublic;
11 | public int MaxPlayers;
12 | public string WorldName;
13 | public string Region;
14 |
15 |
16 | public void Deserialize(DeserializeEvent e)
17 | {
18 | WorldName = e.Reader.ReadString();
19 | IsPublic = e.Reader.ReadBoolean();
20 | MaxPlayers = e.Reader.ReadInt32();
21 | Region = e.Reader.ReadString();
22 | }
23 |
24 | public void Serialize(SerializeEvent e)
25 | {
26 | e.Writer.Write(WorldName);
27 | e.Writer.Write(IsPublic);
28 | e.Writer.Write(MaxPlayers);
29 | e.Writer.Write(Region);
30 | }
31 | }
32 | }
--------------------------------------------------------------------------------
/Utils/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------