Compare commits
178 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
814a9def7f | ||
![]() |
276a4522d6 | ||
![]() |
8b7a07ffe7 | ||
![]() |
f990d27851 | ||
![]() |
3d8bf78213 | ||
![]() |
90479dfea2 | ||
![]() |
844d4be96a | ||
![]() |
9f610d5ae8 | ||
![]() |
c9adb2a212 | ||
![]() |
7fd814d595 | ||
![]() |
e7065a7159 | ||
![]() |
8625db7ae4 | ||
![]() |
68e6774e26 | ||
![]() |
a7c6ae7382 | ||
![]() |
9c06049628 | ||
![]() |
34e5f4df49 | ||
![]() |
b7b58f5870 | ||
![]() |
f9d75856d1 | ||
![]() |
66b7adf485 | ||
![]() |
76637b130c | ||
![]() |
9a1a31c424 | ||
![]() |
faef000245 | ||
![]() |
c2035668cd | ||
![]() |
f1201c6259 | ||
![]() |
bdaa674662 | ||
![]() |
3b17eb4750 | ||
![]() |
9221d412ca | ||
![]() |
65bb71aabf | ||
![]() |
dcd0fa86b9 | ||
![]() |
72be1b8dbf | ||
![]() |
1d7b642c50 | ||
![]() |
f7d45ca338 | ||
![]() |
831722dd84 | ||
![]() |
ee3dd0b5bd | ||
![]() |
7480847677 | ||
![]() |
0ff715af1b | ||
a318aa87cf | |||
![]() |
74b00d3ab1 | ||
![]() |
355375e9db | ||
![]() |
016203d2bc | ||
![]() |
b65efa2968 | ||
![]() |
4fc5f10bad | ||
![]() |
f8e9d68ceb | ||
![]() |
65e8d62391 | ||
![]() |
93fa82201a | ||
![]() |
71930182dd | ||
![]() |
8764540d3b | ||
![]() |
6a6676c1cb | ||
![]() |
5bf91f1891 | ||
![]() |
14e16a959f | ||
![]() |
3b72724966 | ||
![]() |
9a0e7809cd | ||
![]() |
94c25a70b3 | ||
![]() |
4901120be4 | ||
![]() |
21e45b5e45 | ||
![]() |
b829e90edb | ||
![]() |
fbf7fa6176 | ||
![]() |
2b413ef609 | ||
![]() |
0f06ee5688 | ||
![]() |
ec065ec329 | ||
![]() |
c9a5472282 | ||
![]() |
b12199c65b | ||
![]() |
b4ac097910 | ||
![]() |
aae4ec97a9 | ||
![]() |
45d931b351 | ||
![]() |
f53c9660fe | ||
![]() |
c889854818 | ||
![]() |
b8b0a0fcce | ||
![]() |
b3f9d7e5c7 | ||
![]() |
94b457d9c0 | ||
![]() |
0c58655708 | ||
![]() |
ba98e0a15a | ||
![]() |
5496ad1198 | ||
![]() |
7bad6149b5 | ||
![]() |
378905268d | ||
![]() |
f56a700fea | ||
![]() |
736176ce27 | ||
![]() |
96d749c512 | ||
![]() |
17514c89ad | ||
![]() |
8b08f2b747 | ||
![]() |
07bb0fc4cf | ||
![]() |
dbea9d83f4 | ||
![]() |
8989ae94a7 | ||
![]() |
4db83e6f65 | ||
![]() |
9286f2e559 | ||
![]() |
045a572058 | ||
![]() |
f68be8e4c9 | ||
![]() |
ec4572c390 | ||
![]() |
b89b61496b | ||
![]() |
63f504feb7 | ||
![]() |
06eca83ff9 | ||
![]() |
ebc8b7a7fd | ||
![]() |
4c34a653bd | ||
![]() |
38d2f1b62e | ||
![]() |
d8915d1893 | ||
![]() |
873acfcb4f | ||
![]() |
030df5029b | ||
![]() |
7404b6bd2d | ||
![]() |
b9e9be227a | ||
![]() |
f2537706e7 | ||
![]() |
a8251d9385 | ||
![]() |
b1edd62c0b | ||
![]() |
c1e315fa40 | ||
![]() |
bfcf96f1ad | ||
![]() |
d257e9e1e8 | ||
![]() |
85e307f8db | ||
![]() |
03fa0a73b6 | ||
![]() |
2f157a6438 | ||
![]() |
cdde72cbe0 | ||
![]() |
b18420ad55 | ||
![]() |
d92daccdbf | ||
![]() |
6b3cc6c421 | ||
![]() |
18af85c4d7 | ||
![]() |
6c6ff18ec3 | ||
![]() |
67e663f023 | ||
![]() |
3f717b304a | ||
![]() |
300af03012 | ||
![]() |
3d8d333f10 | ||
![]() |
d87cc7f1e7 | ||
![]() |
d59ef20f72 | ||
![]() |
b2bf0229ed | ||
![]() |
f03bfd2d7a | ||
![]() |
3dd646d6e9 | ||
![]() |
58ad553b39 | ||
![]() |
83056bacf4 | ||
![]() |
2751eaf399 | ||
![]() |
869ba0d33c | ||
![]() |
aeb29d9a69 | ||
![]() |
979d5914a9 | ||
![]() |
e72f5b7c37 | ||
![]() |
42d3324fc1 | ||
![]() |
e242ed6f1f | ||
![]() |
a2acb9c11c | ||
![]() |
444da941c9 | ||
![]() |
f19fd84f1d | ||
![]() |
b5793d36a8 | ||
![]() |
a71c03124b | ||
![]() |
66c484796d | ||
![]() |
a4927030d7 | ||
![]() |
c32badb750 | ||
![]() |
356eb849f2 | ||
![]() |
04e949ed0c | ||
![]() |
13dc8622c9 | ||
![]() |
a2b9c4724d | ||
![]() |
f326e569a1 | ||
![]() |
c1961dee5f | ||
![]() |
e42a231553 | ||
![]() |
b3d9a64632 | ||
![]() |
47c7c37fa9 | ||
![]() |
17413f81ff | ||
![]() |
725e555733 | ||
![]() |
6e7456605d | ||
![]() |
b652181dda | ||
![]() |
6764d80534 | ||
![]() |
6fbc06081e | ||
![]() |
0328876d50 | ||
![]() |
c5e1dd7c3a | ||
![]() |
714824df97 | ||
![]() |
2cb921087f | ||
![]() |
1ed3144428 | ||
![]() |
ba8fa01ce5 | ||
![]() |
3f6f077833 | ||
![]() |
74d9999202 | ||
![]() |
1be1c938cc | ||
![]() |
930f1d43e0 | ||
![]() |
1e04053026 | ||
![]() |
1e6b3faff8 | ||
![]() |
e6928b6ab1 | ||
![]() |
eb97d0d479 | ||
![]() |
0a75d57cf9 | ||
![]() |
383c9b9a33 | ||
![]() |
d2adbecc44 | ||
![]() |
834395bdc3 | ||
![]() |
18dad5bedf | ||
![]() |
c188367749 | ||
![]() |
5b098c68aa | ||
![]() |
22bd56652d | ||
![]() |
d07caea0f6 |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,6 +1,9 @@
|
|||||||
## Ignore Visual Studio temporary files, build results, and
|
## Ignore Visual Studio temporary files, build results, and
|
||||||
## files generated by popular Visual Studio add-ons.
|
## files generated by popular Visual Studio add-ons.
|
||||||
|
|
||||||
|
#Rider directory
|
||||||
|
.idea/
|
||||||
|
|
||||||
# User-specific files
|
# User-specific files
|
||||||
*.suo
|
*.suo
|
||||||
*.user
|
*.user
|
||||||
|
7
Jenkinsfile
vendored
7
Jenkinsfile
vendored
@@ -9,9 +9,6 @@ def packageAndArchive(buildMode, packageName, exclude) {
|
|||||||
if (exclude.length() > 0) {
|
if (exclude.length() > 0) {
|
||||||
bat "del ${packageDir}${exclude}"
|
bat "del ${packageDir}${exclude}"
|
||||||
}
|
}
|
||||||
if (buildMode == "Release") {
|
|
||||||
bat "del ${packageDir}*.pdb"
|
|
||||||
}
|
|
||||||
powershell "Add-Type -Assembly System.IO.Compression.FileSystem; [System.IO.Compression.ZipFile]::CreateFromDirectory(\"\$PWD\\${packageDir}\", \"\$PWD\\${zipFile}\")"
|
powershell "Add-Type -Assembly System.IO.Compression.FileSystem; [System.IO.Compression.ZipFile]::CreateFromDirectory(\"\$PWD\\${packageDir}\", \"\$PWD\\${zipFile}\")"
|
||||||
archiveArtifacts artifacts: zipFile, caseSensitive: false, onlyIfSuccessful: true
|
archiveArtifacts artifacts: zipFile, caseSensitive: false, onlyIfSuccessful: true
|
||||||
}
|
}
|
||||||
@@ -50,9 +47,10 @@ node {
|
|||||||
|
|
||||||
packageAndArchive(buildMode, "torch-server", "Torch.Client*")
|
packageAndArchive(buildMode, "torch-server", "Torch.Client*")
|
||||||
|
|
||||||
packageAndArchive(buildMode, "torch-client", "Torch.Server*")
|
/*packageAndArchive(buildMode, "torch-client", "Torch.Server*")*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Disabled because they fail builds more often than they detect actual problems
|
||||||
stage('Test') {
|
stage('Test') {
|
||||||
bat 'IF NOT EXIST reports MKDIR reports'
|
bat 'IF NOT EXIST reports MKDIR reports'
|
||||||
bat "\"packages/xunit.runner.console.2.2.0/tools/xunit.console.exe\" \"bin-test/x64/${buildMode}/Torch.Tests.dll\" \"bin-test/x64/${buildMode}/Torch.Server.Tests.dll\" \"bin-test/x64/${buildMode}/Torch.Client.Tests.dll\" -parallel none -xml \"reports/Torch.Tests.xml\""
|
bat "\"packages/xunit.runner.console.2.2.0/tools/xunit.console.exe\" \"bin-test/x64/${buildMode}/Torch.Tests.dll\" \"bin-test/x64/${buildMode}/Torch.Server.Tests.dll\" \"bin-test/x64/${buildMode}/Torch.Client.Tests.dll\" -parallel none -xml \"reports/Torch.Tests.xml\""
|
||||||
@@ -71,4 +69,5 @@ node {
|
|||||||
]]
|
]]
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
12
NLog.config
12
NLog.config
@@ -4,21 +4,23 @@
|
|||||||
<variable name="logStamp" value="${time} ${pad:padding=-8:inner=[${level:uppercase=true}]}" />
|
<variable name="logStamp" value="${time} ${pad:padding=-8:inner=[${level:uppercase=true}]}" />
|
||||||
<variable name="logContent" value="${message:withException=true}"/>
|
<variable name="logContent" value="${message:withException=true}"/>
|
||||||
|
|
||||||
<targets>
|
<targets async="true">
|
||||||
<target xsi:type="Null" name="null" formatMessage="false" />
|
<target xsi:type="Null" name="null" formatMessage="false" />
|
||||||
<target xsi:type="File" name="keen" layout="${var:logStamp} ${logger}: ${var:logContent}" fileName="Logs\Keen-${shortdate}.log" />
|
<target xsi:type="File" name="keen" layout="${var:logStamp} ${logger}: ${var:logContent}" fileName="Logs\Keen-${shortdate}.log" />
|
||||||
<target xsi:type="File" name="main" layout="${var:logStamp} ${logger}: ${var:logContent}" fileName="Logs\Torch-${shortdate}.log" />
|
<target xsi:type="File" name="main" layout="${var:logStamp} ${logger}: ${var:logContent}" fileName="Logs\Torch-${shortdate}.log" />
|
||||||
<target xsi:type="File" name="chat" layout="${longdate} ${message}" fileName="Logs\Chat.log" />
|
<target xsi:type="File" name="chat" layout="${longdate} ${message}" fileName="Logs\Chat.log" />
|
||||||
<target xsi:type="ColoredConsole" name="console" layout="${var:logStamp} ${logger}: ${var:logContent}" />
|
<target xsi:type="ColoredConsole" name="console" layout="${var:logStamp} ${logger:shortName=true}: ${var:logContent}" />
|
||||||
<target xsi:type="File" name="patch" layout="${var:logContent}" fileName="Logs\patch.log"/>
|
<target xsi:type="File" name="patch" layout="${var:logContent}" fileName="Logs\patch.log"/>
|
||||||
|
<target xsi:type="FlowDocument" name="wpf" layout="${var:logStamp} ${logger:shortName=true}: ${var:logContent}" />
|
||||||
</targets>
|
</targets>
|
||||||
|
|
||||||
<rules>
|
<rules>
|
||||||
<logger name="Keen" minlevel="Info" writeTo="console"/>
|
<logger name="Keen" minlevel="Warn" writeTo="main"/>
|
||||||
|
<logger name="Keen" minlevel="Info" writeTo="console, wpf"/>
|
||||||
<logger name="Keen" minlevel="Debug" writeTo="keen" final="true" />
|
<logger name="Keen" minlevel="Debug" writeTo="keen" final="true" />
|
||||||
<logger name="Keen" writeTo="null" final="true" />
|
<logger name="Keen" writeTo="null" final="true" />
|
||||||
|
|
||||||
<logger name="*" minlevel="Info" writeTo="main, console" />
|
<logger name="*" minlevel="Info" writeTo="main, console, wpf" />
|
||||||
<logger name="Chat" minlevel="Info" writeTo="chat" />
|
<logger name="Chat" minlevel="Info" writeTo="chat" />
|
||||||
<!--<logger name="Torch.Managers.PatchManager.*" minlevel="Trace" writeTo="patch"/>-->
|
<!--<logger name="Torch.Managers.PatchManager.*" minlevel="Trace" writeTo="patch"/>-->
|
||||||
</rules>
|
</rules>
|
||||||
|
12
README.md
12
README.md
@@ -1,4 +1,4 @@
|
|||||||
[](https://discord.gg/8uHZykr) [](http://server.torchapi.net:8080/job/Torch/job/Torch/job/master/)
|
[](https://discord.gg/8uHZykr) [](http://build.torchapi.net/job/Torch/job/Torch/job/master/)
|
||||||
|
|
||||||
# What is Torch?
|
# What is Torch?
|
||||||
Torch is the successor to SE Server Extender and gives server admins the tools they need to keep their Space Engineers servers running smoothly. It features a user interface with live management tools and a plugin system so you can run your server exactly how you'd like. Torch is still in early development so there may be bugs and incomplete features.
|
Torch is the successor to SE Server Extender and gives server admins the tools they need to keep their Space Engineers servers running smoothly. It features a user interface with live management tools and a plugin system so you can run your server exactly how you'd like. Torch is still in early development so there may be bugs and incomplete features.
|
||||||
@@ -14,22 +14,14 @@ Torch is the successor to SE Server Extender and gives server admins the tools t
|
|||||||
|
|
||||||
### Installation
|
### Installation
|
||||||
|
|
||||||
* Get the latest Torch release here: https://github.com/TorchAPI/Torch/releases
|
* Get the latest Torch release here: https://torchapi.net/download
|
||||||
* Unzip the Torch release into its own directory and run the executable. It will automatically download the SE DS and generate the other necessary files.
|
* Unzip the Torch release into its own directory and run the executable. It will automatically download the SE DS and generate the other necessary files.
|
||||||
- If you already have a DS installed you can unzip the Torch files into the folder that contains the DedicatedServer64 folder.
|
- If you already have a DS installed you can unzip the Torch files into the folder that contains the DedicatedServer64 folder.
|
||||||
|
|
||||||
## Torch.Client
|
|
||||||
* An optional client-side version of Torch. More documentation to come.
|
|
||||||
|
|
||||||
# Building
|
# Building
|
||||||
To build Torch you must first have a complete SE Dedicated installation somewhere. Before you open the solution, run the Setup batch file and enter the path of that installation's DedicatedServer64 folder. The script will make a symlink to that folder so the Torch solution can find the DLL references it needs.
|
To build Torch you must first have a complete SE Dedicated installation somewhere. Before you open the solution, run the Setup batch file and enter the path of that installation's DedicatedServer64 folder. The script will make a symlink to that folder so the Torch solution can find the DLL references it needs.
|
||||||
|
|
||||||
In both cases you will need to set the InstancePath in TorchConfig.xml to an existing dedicated server instance as Torch can't fully generate it on its own yet.
|
In both cases you will need to set the InstancePath in TorchConfig.xml to an existing dedicated server instance as Torch can't fully generate it on its own yet.
|
||||||
|
|
||||||
# Official Plugins
|
|
||||||
Install plugins by unzipping them into the 'Plugins' folder which should be in the same location as the Torch files. If it doesn't exist you can simply create it.
|
|
||||||
* [Essentials](https://github.com/TorchAPI/Essentials): Adds a slew of chat commands and other tools to help manage your server.
|
|
||||||
* [Concealment](https://github.com/TorchAPI/Concealment): Adds game logic and physics optimizations that significantly improve sim speed.
|
|
||||||
|
|
||||||
If you have a more enjoyable server experience because of Torch, please consider supporting us on Patreon.
|
If you have a more enjoyable server experience because of Torch, please consider supporting us on Patreon.
|
||||||
[](https://www.patreon.com/bePatron?u=847269)!
|
[](https://www.patreon.com/bePatron?u=847269)!
|
||||||
|
@@ -18,21 +18,25 @@ namespace Torch.API
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Fired when the session begins loading.
|
/// Fired when the session begins loading.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[Obsolete("Prefer using the TorchSessionManager.SessionStateChanged event")]
|
||||||
event Action SessionLoading;
|
event Action SessionLoading;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Fired when the session finishes loading.
|
/// Fired when the session finishes loading.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[Obsolete("Prefer using the TorchSessionManager.SessionStateChanged event")]
|
||||||
event Action SessionLoaded;
|
event Action SessionLoaded;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Fires when the session begins unloading.
|
/// Fires when the session begins unloading.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[Obsolete("Prefer using the TorchSessionManager.SessionStateChanged event")]
|
||||||
event Action SessionUnloading;
|
event Action SessionUnloading;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Fired when the session finishes unloading.
|
/// Fired when the session finishes unloading.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[Obsolete("Prefer using the TorchSessionManager.SessionStateChanged event")]
|
||||||
event Action SessionUnloaded;
|
event Action SessionUnloaded;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -61,7 +65,7 @@ namespace Torch.API
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The binary version of the current instance.
|
/// The binary version of the current instance.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Version TorchVersion { get; }
|
InformationalVersion TorchVersion { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Invoke an action on the game thread.
|
/// Invoke an action on the game thread.
|
||||||
@@ -70,15 +74,23 @@ namespace Torch.API
|
|||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Invoke an action on the game thread and block until it has completed.
|
/// Invoke an action on the game thread and block until it has completed.
|
||||||
/// If this is called on the game thread the action will execute immediately.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void InvokeBlocking(Action action, [CallerMemberName] string caller = "");
|
/// <param name="action">Action to execute</param>
|
||||||
|
/// <param name="caller">Caller of the invoke function</param>
|
||||||
|
/// <param name="timeoutMs">Timeout before <see cref="TimeoutException"/> is thrown, or -1 to never timeout</param>
|
||||||
|
/// <exception cref="TimeoutException">If the action times out</exception>
|
||||||
|
void InvokeBlocking(Action action, int timeoutMs = -1, [CallerMemberName] string caller = "");
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Invoke an action on the game thread asynchronously.
|
/// Invoke an action on the game thread asynchronously.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Task InvokeAsync(Action action, [CallerMemberName] string caller = "");
|
Task InvokeAsync(Action action, [CallerMemberName] string caller = "");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Invoke a function on the game thread asynchronously.
|
||||||
|
/// </summary>
|
||||||
|
Task<T> InvokeAsync<T>(Func<T> func, [CallerMemberName] string caller = "");
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Signals the torch instance to start, then blocks until it's started.
|
/// Signals the torch instance to start, then blocks until it's started.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -90,15 +102,17 @@ namespace Torch.API
|
|||||||
void Stop();
|
void Stop();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Restart the Torch instance.
|
/// Restart the Torch instance, blocking until the restart has been performed.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void Restart();
|
void Restart();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a save of the game.
|
/// Initializes a save of the game.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="callerId">Id of the player who initiated the save.</param>
|
/// <param name="timeoutMs">timeout before the save is treated as failed, or -1 for no timeout</param>
|
||||||
Task Save(long callerId);
|
/// <param name="exclusive">Only start saving if we aren't already saving</param>
|
||||||
|
/// <returns>Future result of the save, or null if one is in progress and in exclusive mode</returns>
|
||||||
|
Task<GameSaveResult> Save(int timeoutMs = -1, bool exclusive = false);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initialize the Torch instance. Before this <see cref="Start"/> is invalid.
|
/// Initialize the Torch instance. Before this <see cref="Start"/> is invalid.
|
||||||
@@ -108,7 +122,7 @@ namespace Torch.API
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Disposes the Torch instance. After this <see cref="Start"/> is invalid.
|
/// Disposes the Torch instance. After this <see cref="Start"/> is invalid.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void Dispose();
|
void Destroy();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The current state of the game this instance of torch is controlling.
|
/// The current state of the game this instance of torch is controlling.
|
||||||
@@ -135,6 +149,11 @@ namespace Torch.API
|
|||||||
/// Path of the dedicated instance folder.
|
/// Path of the dedicated instance folder.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
string InstancePath { get; }
|
string InstancePath { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Raised when the server's Init() method has completed.
|
||||||
|
/// </summary>
|
||||||
|
event Action<ITorchServer> Initialized;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
52
Torch.API/InformationalVersion.cs
Normal file
52
Torch.API/InformationalVersion.cs
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Torch.API
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Version in the form v#.#.#.#-info
|
||||||
|
/// </summary>
|
||||||
|
public class InformationalVersion
|
||||||
|
{
|
||||||
|
public Version Version { get; set; }
|
||||||
|
public string[] Information { get; set; }
|
||||||
|
|
||||||
|
public static bool TryParse(string input, out InformationalVersion version)
|
||||||
|
{
|
||||||
|
version = default(InformationalVersion);
|
||||||
|
var trim = input.TrimStart('v');
|
||||||
|
var info = trim.Split('-');
|
||||||
|
if (!Version.TryParse(info[0], out Version result))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
version = new InformationalVersion { Version = result };
|
||||||
|
|
||||||
|
if (info.Length > 1)
|
||||||
|
version.Information = info.Skip(1).ToArray();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
if (Information == null || Information.Length == 0)
|
||||||
|
return $"v{Version}";
|
||||||
|
|
||||||
|
return $"v{Version}-{string.Join("-", Information)}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static explicit operator InformationalVersion(Version v)
|
||||||
|
{
|
||||||
|
return new InformationalVersion { Version = v };
|
||||||
|
}
|
||||||
|
|
||||||
|
public static implicit operator Version(InformationalVersion v)
|
||||||
|
{
|
||||||
|
return v.Version;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -32,5 +32,15 @@ namespace Torch.API.Managers
|
|||||||
/// <param name="steamId">The SteamID of the player.</param>
|
/// <param name="steamId">The SteamID of the player.</param>
|
||||||
/// <returns>True if the player is banned; otherwise false.</returns>
|
/// <returns>True if the player is banned; otherwise false.</returns>
|
||||||
bool IsBanned(ulong steamId);
|
bool IsBanned(ulong steamId);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Raised when a player is kicked. Passes with SteamID of kicked player.
|
||||||
|
/// </summary>
|
||||||
|
event Action<ulong> PlayerKicked;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Raised when a player is banned or unbanned. Passes SteamID of player, and true if banned, false if unbanned.
|
||||||
|
/// </summary>
|
||||||
|
event Action<ulong, bool> PlayerBanned;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
44
Torch.API/Session/GameSaveResult.cs
Normal file
44
Torch.API/Session/GameSaveResult.cs
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Torch.API.Session
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The result of a save operation
|
||||||
|
/// </summary>
|
||||||
|
public enum GameSaveResult
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Successfully saved
|
||||||
|
/// </summary>
|
||||||
|
Success = 0,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The game wasn't ready to be saved
|
||||||
|
/// </summary>
|
||||||
|
GameNotReady = -1,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Failed to take the snapshot of the current world state
|
||||||
|
/// </summary>
|
||||||
|
FailedToTakeSnapshot = -2,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Failed to save the snapshot to disk
|
||||||
|
/// </summary>
|
||||||
|
FailedToSaveToDisk = -3,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// An unknown error occurred
|
||||||
|
/// </summary>
|
||||||
|
UnknownError = -4,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The save operation timed out
|
||||||
|
/// </summary>
|
||||||
|
TimedOut = -5
|
||||||
|
}
|
||||||
|
}
|
@@ -74,11 +74,6 @@
|
|||||||
<HintPath>..\GameBinaries\SpaceEngineers.ObjectBuilders.XmlSerializers.dll</HintPath>
|
<HintPath>..\GameBinaries\SpaceEngineers.ObjectBuilders.XmlSerializers.dll</HintPath>
|
||||||
<Private>False</Private>
|
<Private>False</Private>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="SteamSDK, Version=0.0.0.0, Culture=neutral, processorArchitecture=AMD64">
|
|
||||||
<SpecificVersion>False</SpecificVersion>
|
|
||||||
<HintPath>..\GameBinaries\SteamSDK.dll</HintPath>
|
|
||||||
<Private>False</Private>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System" />
|
<Reference Include="System" />
|
||||||
<Reference Include="System.Configuration" />
|
<Reference Include="System.Configuration" />
|
||||||
<Reference Include="System.Core" />
|
<Reference Include="System.Core" />
|
||||||
@@ -160,6 +155,7 @@
|
|||||||
<Link>Properties\AssemblyVersion.cs</Link>
|
<Link>Properties\AssemblyVersion.cs</Link>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="ConnectionState.cs" />
|
<Compile Include="ConnectionState.cs" />
|
||||||
|
<Compile Include="InformationalVersion.cs" />
|
||||||
<Compile Include="ITorchConfig.cs" />
|
<Compile Include="ITorchConfig.cs" />
|
||||||
<Compile Include="Managers\DependencyManagerExtensions.cs" />
|
<Compile Include="Managers\DependencyManagerExtensions.cs" />
|
||||||
<Compile Include="Managers\DependencyProviderExtensions.cs" />
|
<Compile Include="Managers\DependencyProviderExtensions.cs" />
|
||||||
@@ -187,6 +183,7 @@
|
|||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
<Compile Include="ServerState.cs" />
|
<Compile Include="ServerState.cs" />
|
||||||
<Compile Include="ModAPI\TorchAPI.cs" />
|
<Compile Include="ModAPI\TorchAPI.cs" />
|
||||||
|
<Compile Include="Session\GameSaveResult.cs" />
|
||||||
<Compile Include="Session\ITorchSession.cs" />
|
<Compile Include="Session\ITorchSession.cs" />
|
||||||
<Compile Include="Session\ITorchSessionManager.cs" />
|
<Compile Include="Session\ITorchSessionManager.cs" />
|
||||||
<Compile Include="Session\TorchSessionState.cs" />
|
<Compile Include="Session\TorchSessionState.cs" />
|
||||||
@@ -198,6 +195,7 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Service Include="{508349B6-6B84-4DF5-91F0-309BEEBAD82D}" />
|
<Service Include="{508349B6-6B84-4DF5-91F0-309BEEBAD82D}" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup />
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
<Import Project="$(SolutionDir)\TransformOnBuild.targets" />
|
<Import Project="$(SolutionDir)\TransformOnBuild.targets" />
|
||||||
</Project>
|
</Project>
|
@@ -90,6 +90,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Service Include="{508349B6-6B84-4DF5-91F0-309BEEBAD82D}" />
|
<Service Include="{508349B6-6B84-4DF5-91F0-309BEEBAD82D}" />
|
||||||
|
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
<Import Project="$(SolutionDir)\TransformOnBuild.targets" />
|
<Import Project="$(SolutionDir)\TransformOnBuild.targets" />
|
||||||
|
@@ -27,6 +27,20 @@ namespace Torch.Client.Manager
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public bool IsBanned(ulong steamId) => false;
|
public bool IsBanned(ulong steamId) => false;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public event Action<ulong> PlayerKicked
|
||||||
|
{
|
||||||
|
add => throw new NotImplementedException();
|
||||||
|
remove => throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public event Action<ulong, bool> PlayerBanned
|
||||||
|
{
|
||||||
|
add => throw new NotImplementedException();
|
||||||
|
remove => throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public override void Attach()
|
public override void Attach()
|
||||||
{
|
{
|
||||||
|
@@ -18,6 +18,7 @@ namespace Torch.Client
|
|||||||
{
|
{
|
||||||
public const string SpaceEngineersBinaries = "Bin64";
|
public const string SpaceEngineersBinaries = "Bin64";
|
||||||
private static string _spaceEngInstallAlias = null;
|
private static string _spaceEngInstallAlias = null;
|
||||||
|
|
||||||
public static string SpaceEngineersInstallAlias
|
public static string SpaceEngineersInstallAlias
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
@@ -26,7 +27,8 @@ namespace Torch.Client
|
|||||||
if (_spaceEngInstallAlias == null)
|
if (_spaceEngInstallAlias == null)
|
||||||
{
|
{
|
||||||
// ReSharper disable once AssignNullToNotNullAttribute
|
// ReSharper disable once AssignNullToNotNullAttribute
|
||||||
_spaceEngInstallAlias = Path.Combine(Path.GetDirectoryName(typeof(Program).Assembly.Location), "SpaceEngineersAlias");
|
_spaceEngInstallAlias = Path.Combine(Path.GetDirectoryName(typeof(Program).Assembly.Location),
|
||||||
|
"SpaceEngineersAlias");
|
||||||
}
|
}
|
||||||
return _spaceEngInstallAlias;
|
return _spaceEngInstallAlias;
|
||||||
}
|
}
|
||||||
@@ -52,16 +54,20 @@ namespace Torch.Client
|
|||||||
{
|
{
|
||||||
AllocConsole();
|
AllocConsole();
|
||||||
#endif
|
#endif
|
||||||
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
|
if (!TorchLauncher.IsTorchWrapped())
|
||||||
|
|
||||||
// Early config: Resolve SE install directory.
|
|
||||||
if (!File.Exists(Path.Combine(SpaceEngineersInstallAlias, _spaceEngineersVerifyFile)))
|
|
||||||
SetupSpaceEngInstallAlias();
|
|
||||||
|
|
||||||
using (new TorchAssemblyResolver(Path.Combine(SpaceEngineersInstallAlias, SpaceEngineersBinaries)))
|
|
||||||
{
|
{
|
||||||
RunClient();
|
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
|
||||||
|
|
||||||
|
// Early config: Resolve SE install directory.
|
||||||
|
if (!File.Exists(Path.Combine(SpaceEngineersInstallAlias, _spaceEngineersVerifyFile)))
|
||||||
|
SetupSpaceEngInstallAlias();
|
||||||
|
|
||||||
|
TorchLauncher.Launch(Assembly.GetEntryAssembly().FullName, args,
|
||||||
|
Path.Combine(SpaceEngineersInstallAlias, SpaceEngineersBinaries));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RunClient();
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
@@ -77,7 +83,8 @@ namespace Torch.Client
|
|||||||
|
|
||||||
// TODO look at Steam/config/Config.VDF? Has alternate directories.
|
// TODO look at Steam/config/Config.VDF? Has alternate directories.
|
||||||
var steamDir =
|
var steamDir =
|
||||||
Microsoft.Win32.Registry.GetValue("HKEY_CURRENT_USER\\SOFTWARE\\Valve\\Steam", "SteamPath", null) as string;
|
Microsoft.Win32.Registry.GetValue("HKEY_CURRENT_USER\\SOFTWARE\\Valve\\Steam", "SteamPath",
|
||||||
|
null) as string;
|
||||||
if (steamDir != null)
|
if (steamDir != null)
|
||||||
{
|
{
|
||||||
spaceEngineersDirectory = Path.Combine(steamDir, _steamSpaceEngineersDirectory);
|
spaceEngineersDirectory = Path.Combine(steamDir, _steamSpaceEngineersDirectory);
|
||||||
@@ -85,7 +92,10 @@ namespace Torch.Client
|
|||||||
if (File.Exists(Path.Combine(spaceEngineersDirectory, _spaceEngineersVerifyFile)))
|
if (File.Exists(Path.Combine(spaceEngineersDirectory, _spaceEngineersVerifyFile)))
|
||||||
_log.Debug("Found Space Engineers in {0}", spaceEngineersDirectory);
|
_log.Debug("Found Space Engineers in {0}", spaceEngineersDirectory);
|
||||||
else
|
else
|
||||||
|
{
|
||||||
_log.Debug("Couldn't find Space Engineers in {0}", spaceEngineersDirectory);
|
_log.Debug("Couldn't find Space Engineers in {0}", spaceEngineersDirectory);
|
||||||
|
spaceEngineersDirectory = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (spaceEngineersDirectory == null)
|
if (spaceEngineersDirectory == null)
|
||||||
{
|
{
|
||||||
@@ -97,7 +107,8 @@ namespace Torch.Client
|
|||||||
{
|
{
|
||||||
if (dialog.ShowDialog() != DialogResult.OK)
|
if (dialog.ShowDialog() != DialogResult.OK)
|
||||||
{
|
{
|
||||||
var ex = new FileNotFoundException("Unable to find the Space Engineers install directory, aborting");
|
var ex = new FileNotFoundException(
|
||||||
|
"Unable to find the Space Engineers install directory, aborting");
|
||||||
_log.Fatal(ex);
|
_log.Fatal(ex);
|
||||||
LogManager.Flush();
|
LogManager.Flush();
|
||||||
throw ex;
|
throw ex;
|
||||||
@@ -109,11 +120,12 @@ namespace Torch.Client
|
|||||||
$"Unable to find {0} in {1}. Are you sure it's the Space Engineers install directory?",
|
$"Unable to find {0} in {1}. Are you sure it's the Space Engineers install directory?",
|
||||||
"Invalid Space Engineers Directory", MessageBoxButton.YesNo) == MessageBoxResult.Yes)
|
"Invalid Space Engineers Directory", MessageBoxButton.YesNo) == MessageBoxResult.Yes)
|
||||||
break;
|
break;
|
||||||
} while (true); // Repeat until they confirm.
|
} while (true); // Repeat until they confirm.
|
||||||
}
|
}
|
||||||
if (!JunctionLink(SpaceEngineersInstallAlias, spaceEngineersDirectory))
|
if (!JunctionLink(SpaceEngineersInstallAlias, spaceEngineersDirectory))
|
||||||
{
|
{
|
||||||
var ex = new IOException($"Failed to create junction link {SpaceEngineersInstallAlias} => {spaceEngineersDirectory}. Aborting.");
|
var ex = new IOException(
|
||||||
|
$"Failed to create junction link {SpaceEngineersInstallAlias} => {spaceEngineersDirectory}. Aborting.");
|
||||||
_log.Fatal(ex);
|
_log.Fatal(ex);
|
||||||
LogManager.Flush();
|
LogManager.Flush();
|
||||||
throw ex;
|
throw ex;
|
||||||
@@ -121,7 +133,8 @@ namespace Torch.Client
|
|||||||
string junctionVerify = Path.Combine(SpaceEngineersInstallAlias, _spaceEngineersVerifyFile);
|
string junctionVerify = Path.Combine(SpaceEngineersInstallAlias, _spaceEngineersVerifyFile);
|
||||||
if (!File.Exists(junctionVerify))
|
if (!File.Exists(junctionVerify))
|
||||||
{
|
{
|
||||||
var ex = new FileNotFoundException($"Junction link is not working. File {junctionVerify} does not exist");
|
var ex = new FileNotFoundException(
|
||||||
|
$"Junction link is not working. File {junctionVerify} does not exist");
|
||||||
_log.Fatal(ex);
|
_log.Fatal(ex);
|
||||||
LogManager.Flush();
|
LogManager.Flush();
|
||||||
throw ex;
|
throw ex;
|
||||||
@@ -153,7 +166,7 @@ namespace Torch.Client
|
|||||||
|
|
||||||
private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
|
private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
|
||||||
{
|
{
|
||||||
var ex = (Exception)e.ExceptionObject;
|
var ex = (Exception) e.ExceptionObject;
|
||||||
_log.Error(ex);
|
_log.Error(ex);
|
||||||
LogManager.Flush();
|
LogManager.Flush();
|
||||||
MessageBox.Show(ex.StackTrace, ex.Message);
|
MessageBox.Show(ex.StackTrace, ex.Message);
|
||||||
|
@@ -26,22 +26,19 @@ namespace Torch.Client
|
|||||||
{
|
{
|
||||||
public class TorchClient : TorchBase, ITorchClient
|
public class TorchClient : TorchBase, ITorchClient
|
||||||
{
|
{
|
||||||
private MyCommonProgramStartup _startup;
|
|
||||||
private IMyRender _renderer;
|
|
||||||
|
|
||||||
protected override uint SteamAppId => 244850;
|
protected override uint SteamAppId => 244850;
|
||||||
protected override string SteamAppName => "Space Engineers";
|
protected override string SteamAppName => "SpaceEngineers";
|
||||||
|
|
||||||
public TorchClient()
|
public TorchClient()
|
||||||
{
|
{
|
||||||
Config = new TorchClientConfig();
|
Config = new TorchClientConfig();
|
||||||
var sessionManager = Managers.GetManager<ITorchSessionManager>();
|
var sessionManager = Managers.GetManager<ITorchSessionManager>();
|
||||||
sessionManager.AddFactory((x) => MyMultiplayer.Static is MyMultiplayerLobby
|
sessionManager.AddFactory((x) => MyMultiplayer.Static is MyMultiplayerLobby
|
||||||
? new MultiplayerManagerLobby(this)
|
? new MultiplayerManagerLobby(this)
|
||||||
: null);
|
: null);
|
||||||
sessionManager.AddFactory((x) => MyMultiplayer.Static is MyMultiplayerClientBase
|
sessionManager.AddFactory((x) => MyMultiplayer.Static is MyMultiplayerClientBase
|
||||||
? new MultiplayerManagerClient(this)
|
? new MultiplayerManagerClient(this)
|
||||||
: null);
|
: null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Init()
|
public override void Init()
|
||||||
@@ -49,38 +46,22 @@ namespace Torch.Client
|
|||||||
Directory.SetCurrentDirectory(Program.SpaceEngineersInstallAlias);
|
Directory.SetCurrentDirectory(Program.SpaceEngineersInstallAlias);
|
||||||
MyFileSystem.ExePath = Path.Combine(Program.SpaceEngineersInstallAlias, Program.SpaceEngineersBinaries);
|
MyFileSystem.ExePath = Path.Combine(Program.SpaceEngineersInstallAlias, Program.SpaceEngineersBinaries);
|
||||||
Log.Info("Initializing Torch Client");
|
Log.Info("Initializing Torch Client");
|
||||||
_startup = new MyCommonProgramStartup(RunArgs);
|
Config.InstancePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
|
||||||
SpaceEngineersGame.SetupBasicGameInfo();
|
SteamAppName);
|
||||||
SpaceEngineersGame.SetupPerGameSettings();
|
|
||||||
if (_startup.PerformReporting())
|
|
||||||
throw new InvalidOperationException("Torch client won't launch when started in error reporting mode");
|
|
||||||
|
|
||||||
_startup.PerformAutoconnect();
|
|
||||||
if (!_startup.CheckSingleInstance())
|
|
||||||
throw new InvalidOperationException("Only one instance of Space Engineers can be running at a time.");
|
|
||||||
|
|
||||||
var appDataPath = _startup.GetAppDataPath();
|
|
||||||
Config.InstancePath = appDataPath;
|
|
||||||
base.Init();
|
base.Init();
|
||||||
OverrideMenus();
|
OverrideMenus();
|
||||||
SetRenderWindowTitle($"Space Engineers v{GameVersion} with Torch v{TorchVersion}");
|
SetRenderWindowTitle($"Space Engineers v{GameVersion} with Torch v{TorchVersion}");
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Dispose()
|
|
||||||
{
|
|
||||||
base.Dispose();
|
|
||||||
_startup.DetectSharpDxLeaksAfterRun();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OverrideMenus()
|
private void OverrideMenus()
|
||||||
{
|
{
|
||||||
var credits = new MyCreditsDepartment("Torch Developed By")
|
var credits = new MyCreditsDepartment("Torch Developed By")
|
||||||
{
|
{
|
||||||
Persons = new List<MyCreditsPerson>
|
Persons = new List<MyCreditsPerson>
|
||||||
{
|
{
|
||||||
new MyCreditsPerson("THE TORCH TEAM"),
|
new MyCreditsPerson("THE TORCH TEAM"),
|
||||||
new MyCreditsPerson("http://github.com/TorchSE"),
|
new MyCreditsPerson("http://github.com/TorchSE"),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
MyPerGameSettings.Credits.Departments.Insert(0, credits);
|
MyPerGameSettings.Credits.Departments.Insert(0, credits);
|
||||||
|
|
||||||
@@ -96,12 +77,11 @@ namespace Torch.Client
|
|||||||
BindingFlags.Instance | BindingFlags.NonPublic);
|
BindingFlags.Instance | BindingFlags.NonPublic);
|
||||||
if (renderWindowField == null)
|
if (renderWindowField == null)
|
||||||
return;
|
return;
|
||||||
var window = renderWindowField.GetValue(MySandboxGame.Static.GameRenderComponent.RenderThread) as System.Windows.Forms.Form;
|
var window =
|
||||||
|
renderWindowField.GetValue(MySandboxGame.Static.GameRenderComponent.RenderThread) as
|
||||||
|
System.Windows.Forms.Form;
|
||||||
if (window != null)
|
if (window != null)
|
||||||
renderThread.Invoke(() =>
|
renderThread.Invoke(() => { window.Text = title; });
|
||||||
{
|
|
||||||
window.Text = title;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Restart()
|
public override void Restart()
|
||||||
|
72
Torch.Mod/Messages/DialogMessage.cs
Normal file
72
Torch.Mod/Messages/DialogMessage.cs
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using ProtoBuf;
|
||||||
|
using Sandbox.ModAPI;
|
||||||
|
|
||||||
|
namespace Torch.Mod.Messages
|
||||||
|
{
|
||||||
|
/// Dialogs are structured as follows
|
||||||
|
///
|
||||||
|
/// _____________________________________
|
||||||
|
/// | Title |
|
||||||
|
/// --------------------------------------
|
||||||
|
/// | Prefix Subtitle |
|
||||||
|
/// --------------------------------------
|
||||||
|
/// | ________________________________ |
|
||||||
|
/// | | Content | |
|
||||||
|
/// | --------------------------------- |
|
||||||
|
/// | ____________ |
|
||||||
|
/// | | ButtonText | |
|
||||||
|
/// | -------------- |
|
||||||
|
/// --------------------------------------
|
||||||
|
///
|
||||||
|
/// Button has a callback on click option,
|
||||||
|
/// but can't serialize that, so ¯\_(ツ)_/¯
|
||||||
|
[ProtoContract]
|
||||||
|
public class DialogMessage : MessageBase
|
||||||
|
{
|
||||||
|
[ProtoMember(201)]
|
||||||
|
public string Title;
|
||||||
|
[ProtoMember(202)]
|
||||||
|
public string Subtitle;
|
||||||
|
[ProtoMember(203)]
|
||||||
|
public string Prefix;
|
||||||
|
[ProtoMember(204)]
|
||||||
|
public string Content;
|
||||||
|
[ProtoMember(205)]
|
||||||
|
public string ButtonText;
|
||||||
|
|
||||||
|
public DialogMessage()
|
||||||
|
{ }
|
||||||
|
|
||||||
|
public DialogMessage(string title, string subtitle, string content)
|
||||||
|
{
|
||||||
|
Title = title;
|
||||||
|
Subtitle = subtitle;
|
||||||
|
Content = content;
|
||||||
|
Prefix = String.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DialogMessage(string title = null, string prefix = null, string subtitle = null, string content = null, string buttonText = null)
|
||||||
|
{
|
||||||
|
Title = title;
|
||||||
|
Subtitle = subtitle;
|
||||||
|
Prefix = prefix ?? String.Empty;
|
||||||
|
Content = content;
|
||||||
|
ButtonText = buttonText;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ProcessClient()
|
||||||
|
{
|
||||||
|
MyAPIGateway.Utilities.ShowMissionScreen(Title, Prefix, Subtitle, Content, null, ButtonText);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ProcessServer()
|
||||||
|
{
|
||||||
|
throw new Exception();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
26
Torch.Mod/Messages/IncomingMessage.cs
Normal file
26
Torch.Mod/Messages/IncomingMessage.cs
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Torch.Mod.Messages
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// shim to store incoming message data
|
||||||
|
/// </summary>
|
||||||
|
internal class IncomingMessage : MessageBase
|
||||||
|
{
|
||||||
|
public IncomingMessage()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ProcessClient()
|
||||||
|
{
|
||||||
|
throw new Exception();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ProcessServer()
|
||||||
|
{
|
||||||
|
throw new Exception();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
51
Torch.Mod/Messages/MessageBase.cs
Normal file
51
Torch.Mod/Messages/MessageBase.cs
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using ProtoBuf;
|
||||||
|
|
||||||
|
namespace Torch.Mod.Messages
|
||||||
|
{
|
||||||
|
#region Includes
|
||||||
|
[ProtoInclude(1, typeof(DialogMessage))]
|
||||||
|
[ProtoInclude(2, typeof(NotificationMessage))]
|
||||||
|
[ProtoInclude(3, typeof(VoxelResetMessage))]
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
[ProtoContract]
|
||||||
|
public abstract class MessageBase
|
||||||
|
{
|
||||||
|
[ProtoMember(101)]
|
||||||
|
public ulong SenderId;
|
||||||
|
|
||||||
|
public abstract void ProcessClient();
|
||||||
|
public abstract void ProcessServer();
|
||||||
|
|
||||||
|
//members below not serialized, they're just metadata about the intended target(s) of this message
|
||||||
|
internal MessageTarget TargetType;
|
||||||
|
internal ulong Target;
|
||||||
|
internal ulong[] Ignore;
|
||||||
|
internal byte[] CompressedData;
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum MessageTarget
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Send to Target
|
||||||
|
/// </summary>
|
||||||
|
Single,
|
||||||
|
/// <summary>
|
||||||
|
/// Send to Server
|
||||||
|
/// </summary>
|
||||||
|
Server,
|
||||||
|
/// <summary>
|
||||||
|
/// Send to all Clients (only valid from server)
|
||||||
|
/// </summary>
|
||||||
|
AllClients,
|
||||||
|
/// <summary>
|
||||||
|
/// Send to all except those steam ID listed in Ignore
|
||||||
|
/// </summary>
|
||||||
|
AllExcept,
|
||||||
|
}
|
||||||
|
}
|
39
Torch.Mod/Messages/NotificationMessage.cs
Normal file
39
Torch.Mod/Messages/NotificationMessage.cs
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
using ProtoBuf;
|
||||||
|
using Sandbox.ModAPI;
|
||||||
|
|
||||||
|
namespace Torch.Mod.Messages
|
||||||
|
{
|
||||||
|
[ProtoContract]
|
||||||
|
public class NotificationMessage : MessageBase
|
||||||
|
{
|
||||||
|
[ProtoMember(201)]
|
||||||
|
public string Message;
|
||||||
|
[ProtoMember(202)]
|
||||||
|
public string Font;
|
||||||
|
[ProtoMember(203)]
|
||||||
|
public int DisappearTimeMs;
|
||||||
|
|
||||||
|
public NotificationMessage()
|
||||||
|
{ }
|
||||||
|
|
||||||
|
public NotificationMessage(string message, int disappearTimeMs, string font)
|
||||||
|
{
|
||||||
|
Message = message;
|
||||||
|
DisappearTimeMs = disappearTimeMs;
|
||||||
|
Font = font;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ProcessClient()
|
||||||
|
{
|
||||||
|
MyAPIGateway.Utilities.ShowNotification(Message, DisappearTimeMs, Font);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ProcessServer()
|
||||||
|
{
|
||||||
|
throw new Exception();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
44
Torch.Mod/Messages/VoxelResetMessage.cs
Normal file
44
Torch.Mod/Messages/VoxelResetMessage.cs
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
using ProtoBuf;
|
||||||
|
using Sandbox.ModAPI;
|
||||||
|
using VRage.ModAPI;
|
||||||
|
using VRage.Voxels;
|
||||||
|
|
||||||
|
namespace Torch.Mod.Messages
|
||||||
|
{
|
||||||
|
[ProtoContract]
|
||||||
|
public class VoxelResetMessage : MessageBase
|
||||||
|
{
|
||||||
|
[ProtoMember(201)]
|
||||||
|
public long[] EntityId;
|
||||||
|
|
||||||
|
public VoxelResetMessage()
|
||||||
|
{ }
|
||||||
|
|
||||||
|
public VoxelResetMessage(long[] entityId)
|
||||||
|
{
|
||||||
|
EntityId = entityId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ProcessClient()
|
||||||
|
{
|
||||||
|
//MyAPIGateway.Parallel.ForEach(EntityId, id =>
|
||||||
|
foreach (var id in EntityId)
|
||||||
|
{
|
||||||
|
IMyEntity e;
|
||||||
|
if (!MyAPIGateway.Entities.TryGetEntityById(id, out e))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var v = e as IMyVoxelBase;
|
||||||
|
v?.Storage.Reset(MyStorageDataTypeFlags.All);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ProcessServer()
|
||||||
|
{
|
||||||
|
throw new Exception();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
189
Torch.Mod/ModCommunication.cs
Normal file
189
Torch.Mod/ModCommunication.cs
Normal file
@@ -0,0 +1,189 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Sandbox.ModAPI;
|
||||||
|
using Torch.Mod.Messages;
|
||||||
|
using VRage;
|
||||||
|
using VRage.Collections;
|
||||||
|
using VRage.Game.ModAPI;
|
||||||
|
using VRage.Utils;
|
||||||
|
using Task = ParallelTasks.Task;
|
||||||
|
|
||||||
|
namespace Torch.Mod
|
||||||
|
{
|
||||||
|
public static class ModCommunication
|
||||||
|
{
|
||||||
|
public const ushort NET_ID = 4352;
|
||||||
|
private static bool _closing = false;
|
||||||
|
private static BlockingCollection<MessageBase> _processing;
|
||||||
|
private static MyConcurrentPool<IncomingMessage> _messagePool;
|
||||||
|
private static List<IMyPlayer> _playerCache;
|
||||||
|
|
||||||
|
public static void Register()
|
||||||
|
{
|
||||||
|
MyLog.Default.WriteLineAndConsole("TORCH MOD: Registering mod communication.");
|
||||||
|
_processing = new BlockingCollection<MessageBase>(new ConcurrentQueue<MessageBase>());
|
||||||
|
_playerCache = new List<IMyPlayer>();
|
||||||
|
_messagePool = new MyConcurrentPool<IncomingMessage>(8);
|
||||||
|
|
||||||
|
MyAPIGateway.Multiplayer.RegisterMessageHandler(NET_ID, MessageHandler);
|
||||||
|
//background thread to handle de/compression and processing
|
||||||
|
_closing = false;
|
||||||
|
MyAPIGateway.Parallel.StartBackground(DoProcessing);
|
||||||
|
MyLog.Default.WriteLineAndConsole("TORCH MOD: Mod communication registered successfully.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Unregister()
|
||||||
|
{
|
||||||
|
MyLog.Default.WriteLineAndConsole("TORCH MOD: Unregistering mod communication.");
|
||||||
|
MyAPIGateway.Multiplayer?.UnregisterMessageHandler(NET_ID, MessageHandler);
|
||||||
|
_processing?.CompleteAdding();
|
||||||
|
_closing = true;
|
||||||
|
//_task.Wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void MessageHandler(byte[] bytes)
|
||||||
|
{
|
||||||
|
var m = _messagePool.Get();
|
||||||
|
m.CompressedData = bytes;
|
||||||
|
_processing.Add(m);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void DoProcessing()
|
||||||
|
{
|
||||||
|
while (!_closing)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var m = _processing.Take();
|
||||||
|
MyLog.Default.WriteLineAndConsole($"Processing message: {m.GetType().Name}");
|
||||||
|
|
||||||
|
if (m is IncomingMessage)
|
||||||
|
{
|
||||||
|
MessageBase i;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var o = MyCompression.Decompress(m.CompressedData);
|
||||||
|
m.CompressedData = null;
|
||||||
|
_messagePool.Return((IncomingMessage)m);
|
||||||
|
i = MyAPIGateway.Utilities.SerializeFromBinary<MessageBase>(o);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
MyLog.Default.WriteLineAndConsole($"TORCH MOD: Failed to deserialize message! {ex}");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (MyAPIGateway.Multiplayer.IsServer)
|
||||||
|
i.ProcessServer();
|
||||||
|
else
|
||||||
|
i.ProcessClient();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var b = MyAPIGateway.Utilities.SerializeToBinary(m);
|
||||||
|
m.CompressedData = MyCompression.Compress(b);
|
||||||
|
|
||||||
|
MyAPIGateway.Utilities.InvokeOnGameThread(() =>
|
||||||
|
{
|
||||||
|
|
||||||
|
switch (m.TargetType)
|
||||||
|
{
|
||||||
|
case MessageTarget.Single:
|
||||||
|
MyAPIGateway.Multiplayer.SendMessageTo(NET_ID, m.CompressedData, m.Target);
|
||||||
|
break;
|
||||||
|
case MessageTarget.Server:
|
||||||
|
MyAPIGateway.Multiplayer.SendMessageToServer(NET_ID, m.CompressedData);
|
||||||
|
break;
|
||||||
|
case MessageTarget.AllClients:
|
||||||
|
MyAPIGateway.Players.GetPlayers(_playerCache);
|
||||||
|
foreach (var p in _playerCache)
|
||||||
|
{
|
||||||
|
if (p.SteamUserId == MyAPIGateway.Multiplayer.MyId)
|
||||||
|
continue;
|
||||||
|
MyAPIGateway.Multiplayer.SendMessageTo(NET_ID, m.CompressedData, p.SteamUserId);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MessageTarget.AllExcept:
|
||||||
|
MyAPIGateway.Players.GetPlayers(_playerCache);
|
||||||
|
foreach (var p in _playerCache)
|
||||||
|
{
|
||||||
|
if (p.SteamUserId == MyAPIGateway.Multiplayer.MyId || m.Ignore.Contains(p.SteamUserId))
|
||||||
|
continue;
|
||||||
|
MyAPIGateway.Multiplayer.SendMessageTo(NET_ID, m.CompressedData, p.SteamUserId);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Exception();
|
||||||
|
}
|
||||||
|
_playerCache.Clear();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
MyLog.Default.WriteLineAndConsole($"TORCH MOD: Exception occurred in communication thread! {ex}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MyLog.Default.WriteLineAndConsole("TORCH MOD: COMMUNICATION THREAD: EXIT SIGNAL RECEIVED!");
|
||||||
|
//exit signal received. Clean everything and GTFO
|
||||||
|
_processing?.Dispose();
|
||||||
|
_processing = null;
|
||||||
|
_messagePool?.Clean();
|
||||||
|
_messagePool = null;
|
||||||
|
_playerCache = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SendMessageTo(MessageBase message, ulong target)
|
||||||
|
{
|
||||||
|
if (!MyAPIGateway.Multiplayer.IsServer)
|
||||||
|
throw new Exception("Only server can send targeted messages");
|
||||||
|
|
||||||
|
if (_closing)
|
||||||
|
return;
|
||||||
|
|
||||||
|
message.Target = target;
|
||||||
|
message.TargetType = MessageTarget.Single;
|
||||||
|
_processing.Add(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SendMessageToClients(MessageBase message)
|
||||||
|
{
|
||||||
|
if (!MyAPIGateway.Multiplayer.IsServer)
|
||||||
|
throw new Exception("Only server can send targeted messages");
|
||||||
|
|
||||||
|
if (_closing)
|
||||||
|
return;
|
||||||
|
|
||||||
|
message.TargetType = MessageTarget.AllClients;
|
||||||
|
_processing.Add(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SendMessageExcept(MessageBase message, params ulong[] ignoredUsers)
|
||||||
|
{
|
||||||
|
if (!MyAPIGateway.Multiplayer.IsServer)
|
||||||
|
throw new Exception("Only server can send targeted messages");
|
||||||
|
|
||||||
|
if (_closing)
|
||||||
|
return;
|
||||||
|
|
||||||
|
message.TargetType = MessageTarget.AllExcept;
|
||||||
|
message.Ignore = ignoredUsers;
|
||||||
|
_processing.Add(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SendMessageToServer(MessageBase message)
|
||||||
|
{
|
||||||
|
if (_closing)
|
||||||
|
return;
|
||||||
|
|
||||||
|
message.TargetType = MessageTarget.Server;
|
||||||
|
_processing.Add(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
20
Torch.Mod/Torch.Mod.projitems
Normal file
20
Torch.Mod/Torch.Mod.projitems
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<PropertyGroup>
|
||||||
|
<MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
|
||||||
|
<HasSharedItems>true</HasSharedItems>
|
||||||
|
<SharedGUID>3ce4d2e9-b461-4f19-8233-f87e0dfddd74</SharedGUID>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Label="Configuration">
|
||||||
|
<Import_RootNamespace>Torch.Mod</Import_RootNamespace>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="$(MSBuildThisFileDirectory)Messages\IncomingMessage.cs" />
|
||||||
|
<Compile Include="$(MSBuildThisFileDirectory)Messages\NotificationMessage.cs" />
|
||||||
|
<Compile Include="$(MSBuildThisFileDirectory)Messages\DialogMessage.cs" />
|
||||||
|
<Compile Include="$(MSBuildThisFileDirectory)Messages\MessageBase.cs" />
|
||||||
|
<Compile Include="$(MSBuildThisFileDirectory)Messages\VoxelResetMessage.cs" />
|
||||||
|
<Compile Include="$(MSBuildThisFileDirectory)ModCommunication.cs" />
|
||||||
|
<Compile Include="$(MSBuildThisFileDirectory)TorchModCore.cs" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
13
Torch.Mod/Torch.Mod.shproj
Normal file
13
Torch.Mod/Torch.Mod.shproj
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<PropertyGroup Label="Globals">
|
||||||
|
<ProjectGuid>3ce4d2e9-b461-4f19-8233-f87e0dfddd74</ProjectGuid>
|
||||||
|
<MinimumVisualStudioVersion>14.0</MinimumVisualStudioVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||||
|
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.Default.props" />
|
||||||
|
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.props" />
|
||||||
|
<PropertyGroup />
|
||||||
|
<Import Project="Torch.Mod.projitems" Label="Shared" />
|
||||||
|
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.CSharp.targets" />
|
||||||
|
</Project>
|
37
Torch.Mod/TorchModCore.cs
Normal file
37
Torch.Mod/TorchModCore.cs
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using VRage.Game.Components;
|
||||||
|
|
||||||
|
namespace Torch.Mod
|
||||||
|
{
|
||||||
|
[MySessionComponentDescriptor(MyUpdateOrder.AfterSimulation)]
|
||||||
|
public class TorchModCore : MySessionComponentBase
|
||||||
|
{
|
||||||
|
public const ulong MOD_ID = 1406994352;
|
||||||
|
private static bool _init;
|
||||||
|
|
||||||
|
public override void UpdateAfterSimulation()
|
||||||
|
{
|
||||||
|
if (_init)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_init = true;
|
||||||
|
ModCommunication.Register();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void UnloadData()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ModCommunication.Unregister();
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
//session unloading, don't care
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -39,6 +39,7 @@
|
|||||||
<Private>True</Private>
|
<Private>True</Private>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="System" />
|
<Reference Include="System" />
|
||||||
|
<Reference Include="System.ComponentModel.DataAnnotations" />
|
||||||
<Reference Include="System.Core" />
|
<Reference Include="System.Core" />
|
||||||
<Reference Include="System.Xml.Linq" />
|
<Reference Include="System.Xml.Linq" />
|
||||||
<Reference Include="System.Data.DataSetExtensions" />
|
<Reference Include="System.Data.DataSetExtensions" />
|
||||||
@@ -46,6 +47,10 @@
|
|||||||
<Reference Include="System.Data" />
|
<Reference Include="System.Data" />
|
||||||
<Reference Include="System.Net.Http" />
|
<Reference Include="System.Net.Http" />
|
||||||
<Reference Include="System.Xml" />
|
<Reference Include="System.Xml" />
|
||||||
|
<Reference Include="VRage.Game, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||||
|
<SpecificVersion>False</SpecificVersion>
|
||||||
|
<HintPath>..\GameBinaries\VRage.Game.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
<Reference Include="xunit.abstractions, Version=2.0.0.0, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL">
|
<Reference Include="xunit.abstractions, Version=2.0.0.0, Culture=neutral, PublicKeyToken=8d05b1bb7a6fdb6c, processorArchitecture=MSIL">
|
||||||
<HintPath>..\packages\xunit.abstractions.2.0.1\lib\net35\xunit.abstractions.dll</HintPath>
|
<HintPath>..\packages\xunit.abstractions.2.0.1\lib\net35\xunit.abstractions.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
@@ -65,6 +70,7 @@
|
|||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
<Compile Include="TorchServerReflectionTest.cs" />
|
<Compile Include="TorchServerReflectionTest.cs" />
|
||||||
|
<Compile Include="TorchServerSessionSettingsTest.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Torch.API\Torch.API.csproj">
|
<ProjectReference Include="..\Torch.API\Torch.API.csproj">
|
||||||
@@ -88,6 +94,9 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="packages.config" />
|
<None Include="packages.config" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
|
||||||
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
<Import Project="$(SolutionDir)\TransformOnBuild.targets" />
|
<Import Project="$(SolutionDir)\TransformOnBuild.targets" />
|
||||||
</Project>
|
</Project>
|
@@ -6,6 +6,7 @@ using Xunit;
|
|||||||
|
|
||||||
namespace Torch.Server.Tests
|
namespace Torch.Server.Tests
|
||||||
{
|
{
|
||||||
|
#warning Disabled reflection tests because of seemingly random failures
|
||||||
public class TorchServerReflectionTest
|
public class TorchServerReflectionTest
|
||||||
{
|
{
|
||||||
static TorchServerReflectionTest()
|
static TorchServerReflectionTest()
|
||||||
@@ -34,7 +35,7 @@ namespace Torch.Server.Tests
|
|||||||
public static IEnumerable<object[]> Events => Manager().Events;
|
public static IEnumerable<object[]> Events => Manager().Events;
|
||||||
|
|
||||||
#region Binding
|
#region Binding
|
||||||
[Theory]
|
//[Theory]
|
||||||
[MemberData(nameof(Getters))]
|
[MemberData(nameof(Getters))]
|
||||||
public void TestBindingGetter(ReflectionTestManager.FieldRef field)
|
public void TestBindingGetter(ReflectionTestManager.FieldRef field)
|
||||||
{
|
{
|
||||||
@@ -45,7 +46,7 @@ namespace Torch.Server.Tests
|
|||||||
Assert.NotNull(field.Field.GetValue(null));
|
Assert.NotNull(field.Field.GetValue(null));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
//[Theory]
|
||||||
[MemberData(nameof(Setters))]
|
[MemberData(nameof(Setters))]
|
||||||
public void TestBindingSetter(ReflectionTestManager.FieldRef field)
|
public void TestBindingSetter(ReflectionTestManager.FieldRef field)
|
||||||
{
|
{
|
||||||
@@ -56,7 +57,7 @@ namespace Torch.Server.Tests
|
|||||||
Assert.NotNull(field.Field.GetValue(null));
|
Assert.NotNull(field.Field.GetValue(null));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
//[Theory]
|
||||||
[MemberData(nameof(Invokers))]
|
[MemberData(nameof(Invokers))]
|
||||||
public void TestBindingInvoker(ReflectionTestManager.FieldRef field)
|
public void TestBindingInvoker(ReflectionTestManager.FieldRef field)
|
||||||
{
|
{
|
||||||
@@ -67,7 +68,7 @@ namespace Torch.Server.Tests
|
|||||||
Assert.NotNull(field.Field.GetValue(null));
|
Assert.NotNull(field.Field.GetValue(null));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
//[Theory]
|
||||||
[MemberData(nameof(Events))]
|
[MemberData(nameof(Events))]
|
||||||
public void TestBindingEvents(ReflectionTestManager.FieldRef field)
|
public void TestBindingEvents(ReflectionTestManager.FieldRef field)
|
||||||
{
|
{
|
||||||
|
34
Torch.Server.Tests/TorchServerSessionSettingsTest.cs
Normal file
34
Torch.Server.Tests/TorchServerSessionSettingsTest.cs
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Torch.Server.ViewModels;
|
||||||
|
using VRage.Game;
|
||||||
|
using Xunit;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
|
||||||
|
namespace Torch.Server.Tests
|
||||||
|
{
|
||||||
|
public class TorchServerSessionSettingsTest
|
||||||
|
{
|
||||||
|
public static PropertyInfo[] ViewModelProperties = typeof(SessionSettingsViewModel).GetProperties(BindingFlags.Public | BindingFlags.Instance);
|
||||||
|
public static IEnumerable<object[]> ModelFields = typeof(MyObjectBuilder_SessionSettings).GetFields(BindingFlags.Public | BindingFlags.Instance).Select(x => new object[] { x });
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[MemberData(nameof(ModelFields))]
|
||||||
|
public void MissingPropertyTest(FieldInfo modelField)
|
||||||
|
{
|
||||||
|
// Ignore fields that aren't applicable to SE
|
||||||
|
if (modelField.GetCustomAttribute<GameRelationAttribute>()?.RelatedTo == Game.MedievalEngineers)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(modelField.GetCustomAttribute<DisplayAttribute>()?.Name))
|
||||||
|
return;
|
||||||
|
|
||||||
|
var match = ViewModelProperties.FirstOrDefault(p => p.Name.Equals(modelField.Name, StringComparison.InvariantCultureIgnoreCase));
|
||||||
|
Assert.NotNull(match);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
65
Torch.Server/Commands/WhitelistCommands.cs
Normal file
65
Torch.Server/Commands/WhitelistCommands.cs
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Torch.Commands;
|
||||||
|
|
||||||
|
namespace Torch.Server.Commands
|
||||||
|
{
|
||||||
|
[Category("whitelist")]
|
||||||
|
public class WhitelistCommands : CommandModule
|
||||||
|
{
|
||||||
|
private TorchConfig Config => (TorchConfig)Context.Torch.Config;
|
||||||
|
|
||||||
|
[Command("on", "Enables the whitelist.")]
|
||||||
|
public void On()
|
||||||
|
{
|
||||||
|
if (!Config.EnableWhitelist)
|
||||||
|
{
|
||||||
|
Config.EnableWhitelist = true;
|
||||||
|
Context.Respond("Whitelist enabled.");
|
||||||
|
Config.Save();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Context.Respond("Whitelist is already enabled.");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command("off", "Disables the whitelist")]
|
||||||
|
public void Off()
|
||||||
|
{
|
||||||
|
if (Config.EnableWhitelist)
|
||||||
|
{
|
||||||
|
Config.EnableWhitelist = false;
|
||||||
|
Context.Respond("Whitelist disabled.");
|
||||||
|
Config.Save();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Context.Respond("Whitelist is already disabled.");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command("add", "Add a Steam ID to the whitelist.")]
|
||||||
|
public void Add(ulong steamId)
|
||||||
|
{
|
||||||
|
if (Config.Whitelist.Add(steamId))
|
||||||
|
{
|
||||||
|
Context.Respond($"Added {steamId} to the whitelist.");
|
||||||
|
Config.Save();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Context.Respond($"{steamId} is already whitelisted.");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Command("remove", "Remove a Steam ID from the whitelist.")]
|
||||||
|
public void Remove(ulong steamId)
|
||||||
|
{
|
||||||
|
if (Config.Whitelist.Remove(steamId))
|
||||||
|
{
|
||||||
|
Context.Respond($"Removed {steamId} from the whitelist.");
|
||||||
|
Config.Save();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Context.Respond($"{steamId} is not whitelisted.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
54
Torch.Server/FlowDocumentTarget.cs
Normal file
54
Torch.Server/FlowDocumentTarget.cs
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows.Documents;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using NLog;
|
||||||
|
using NLog.Targets;
|
||||||
|
|
||||||
|
namespace Torch.Server
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// NLog target that writes to a <see cref="FlowDocument"/>.
|
||||||
|
/// </summary>
|
||||||
|
[Target("flowDocument")]
|
||||||
|
public sealed class FlowDocumentTarget : TargetWithLayout
|
||||||
|
{
|
||||||
|
private FlowDocument _document = new FlowDocument { Background = new SolidColorBrush(Colors.Black) };
|
||||||
|
private readonly Paragraph _paragraph = new Paragraph();
|
||||||
|
private readonly int _maxLines = 500;
|
||||||
|
|
||||||
|
public FlowDocument Document => _document;
|
||||||
|
|
||||||
|
public FlowDocumentTarget()
|
||||||
|
{
|
||||||
|
_document.Blocks.Add(_paragraph);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Write(LogEventInfo logEvent)
|
||||||
|
{
|
||||||
|
_document.Dispatcher.BeginInvoke(() =>
|
||||||
|
{
|
||||||
|
var message = $"{Layout.Render(logEvent)}\n";
|
||||||
|
_paragraph.Inlines.Add(new Run(message) {Foreground = LogLevelColors[logEvent.Level]});
|
||||||
|
|
||||||
|
// A massive paragraph slows the UI down
|
||||||
|
if (_paragraph.Inlines.Count > _maxLines)
|
||||||
|
_paragraph.Inlines.Remove(_paragraph.Inlines.FirstInline);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private static readonly Dictionary<LogLevel, SolidColorBrush> LogLevelColors = new Dictionary<LogLevel, SolidColorBrush>
|
||||||
|
{
|
||||||
|
[LogLevel.Trace] = new SolidColorBrush(Colors.DimGray),
|
||||||
|
[LogLevel.Debug] = new SolidColorBrush(Colors.DarkGray),
|
||||||
|
[LogLevel.Info] = new SolidColorBrush(Colors.White),
|
||||||
|
[LogLevel.Warn] = new SolidColorBrush(Colors.Magenta),
|
||||||
|
[LogLevel.Error] = new SolidColorBrush(Colors.Yellow),
|
||||||
|
[LogLevel.Fatal] = new SolidColorBrush(Colors.Red),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
@@ -9,9 +9,14 @@ using System.Reflection;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows;
|
||||||
using System.Windows.Threading;
|
using System.Windows.Threading;
|
||||||
using NLog;
|
using NLog;
|
||||||
|
using NLog.Targets;
|
||||||
|
using Sandbox.Engine.Utils;
|
||||||
using Torch.Utils;
|
using Torch.Utils;
|
||||||
|
using VRage.FileSystem;
|
||||||
|
using VRage.Library.Exceptions;
|
||||||
|
|
||||||
namespace Torch.Server
|
namespace Torch.Server
|
||||||
{
|
{
|
||||||
@@ -23,6 +28,7 @@ namespace Torch.Server
|
|||||||
private const string STEAMCMD_ZIP = "temp.zip";
|
private const string STEAMCMD_ZIP = "temp.zip";
|
||||||
private static readonly string STEAMCMD_PATH = $"{STEAMCMD_DIR}\\steamcmd.exe";
|
private static readonly string STEAMCMD_PATH = $"{STEAMCMD_DIR}\\steamcmd.exe";
|
||||||
private static readonly string RUNSCRIPT_PATH = $"{STEAMCMD_DIR}\\runscript.txt";
|
private static readonly string RUNSCRIPT_PATH = $"{STEAMCMD_DIR}\\runscript.txt";
|
||||||
|
|
||||||
private const string RUNSCRIPT = @"force_install_dir ../
|
private const string RUNSCRIPT = @"force_install_dir ../
|
||||||
login anonymous
|
login anonymous
|
||||||
app_update 298740
|
app_update 298740
|
||||||
@@ -49,9 +55,17 @@ quit";
|
|||||||
AppDomain.CurrentDomain.UnhandledException += HandleException;
|
AppDomain.CurrentDomain.UnhandledException += HandleException;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!args.Contains("-noupdate"))
|
// This is what happens when Keen is bad and puts extensions into the System namespace.
|
||||||
|
if (!Enumerable.Contains(args, "-noupdate"))
|
||||||
RunSteamCmd();
|
RunSteamCmd();
|
||||||
|
|
||||||
|
var basePath = new FileInfo(typeof(Program).Assembly.Location).Directory.ToString();
|
||||||
|
var apiSource = Path.Combine(basePath, "DedicatedServer64", "steam_api64.dll");
|
||||||
|
var apiTarget = Path.Combine(basePath, "steam_api64.dll");
|
||||||
|
|
||||||
|
if (!File.Exists(apiTarget))
|
||||||
|
File.Copy(apiSource, apiTarget);
|
||||||
|
|
||||||
_config = InitConfig();
|
_config = InitConfig();
|
||||||
if (!_config.Parse(args))
|
if (!_config.Parse(args))
|
||||||
return false;
|
return false;
|
||||||
@@ -69,7 +83,6 @@ quit";
|
|||||||
Console.Write(".");
|
Console.Write(".");
|
||||||
Thread.Sleep(1000);
|
Thread.Sleep(1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
@@ -84,17 +97,29 @@ quit";
|
|||||||
public void Run()
|
public void Run()
|
||||||
{
|
{
|
||||||
_server = new TorchServer(_config);
|
_server = new TorchServer(_config);
|
||||||
_server.Init();
|
var init = Task.Run(() => _server.Init()).ContinueWith(x =>
|
||||||
|
{
|
||||||
|
if (!x.IsFaulted)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Log.Error("Error initializing server.");
|
||||||
|
LogException(x.Exception);
|
||||||
|
});
|
||||||
if (!_config.NoGui)
|
if (!_config.NoGui)
|
||||||
{
|
{
|
||||||
var ui = new TorchUI(_server);
|
|
||||||
if (_config.Autostart)
|
if (_config.Autostart)
|
||||||
_server.Start();
|
init.ContinueWith(x => _server.Start());
|
||||||
ui.ShowDialog();
|
|
||||||
|
Log.Info("Showing UI");
|
||||||
|
Console.SetOut(TextWriter.Null);
|
||||||
|
NativeMethods.FreeConsole();
|
||||||
|
new TorchUI(_server).ShowDialog();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
init.Wait();
|
||||||
_server.Start();
|
_server.Start();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private TorchConfig InitConfig()
|
private TorchConfig InitConfig()
|
||||||
@@ -109,13 +134,13 @@ quit";
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
Log.Info($"Generating default config at {configPath}");
|
Log.Info($"Generating default config at {configPath}");
|
||||||
var config = new TorchConfig { InstancePath = Path.GetFullPath("Instance") };
|
var config = new TorchConfig {InstancePath = Path.GetFullPath("Instance")};
|
||||||
config.Save(configPath);
|
config.Save(configPath);
|
||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void RunSteamCmd()
|
public static void RunSteamCmd()
|
||||||
{
|
{
|
||||||
var log = LogManager.GetLogger("SteamCMD");
|
var log = LogManager.GetLogger("SteamCMD");
|
||||||
|
|
||||||
@@ -170,26 +195,43 @@ quit";
|
|||||||
{
|
{
|
||||||
LogException(ex.InnerException);
|
LogException(ex.InnerException);
|
||||||
}
|
}
|
||||||
|
|
||||||
Log.Fatal(ex);
|
Log.Fatal(ex);
|
||||||
|
|
||||||
if (ex is ReflectionTypeLoadException exti)
|
if (ex is ReflectionTypeLoadException exti)
|
||||||
foreach (Exception exl in exti.LoaderExceptions)
|
foreach (Exception exl in exti.LoaderExceptions)
|
||||||
LogException(exl);
|
LogException(exl);
|
||||||
|
|
||||||
|
if (ex is AggregateException ag)
|
||||||
|
foreach (Exception e in ag.InnerExceptions)
|
||||||
|
LogException(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleException(object sender, UnhandledExceptionEventArgs e)
|
private void HandleException(object sender, UnhandledExceptionEventArgs e)
|
||||||
{
|
{
|
||||||
var ex = (Exception)e.ExceptionObject;
|
var ex = (Exception)e.ExceptionObject;
|
||||||
LogException(ex);
|
LogException(ex);
|
||||||
Console.WriteLine("Exiting in 5 seconds.");
|
if (MyFakes.ENABLE_MINIDUMP_SENDING)
|
||||||
Thread.Sleep(5000);
|
{
|
||||||
|
string path = Path.Combine(MyFileSystem.UserDataPath, "Minidump.dmp");
|
||||||
|
Log.Info($"Generating minidump at {path}");
|
||||||
|
MyMiniDump.Options options = MyMiniDump.Options.WithProcessThreadData | MyMiniDump.Options.WithThreadInfo;
|
||||||
|
MyMiniDump.Write(path, options, MyMiniDump.ExceptionInfo.Present);
|
||||||
|
}
|
||||||
LogManager.Flush();
|
LogManager.Flush();
|
||||||
if (_config.RestartOnCrash)
|
if (_config.RestartOnCrash)
|
||||||
{
|
{
|
||||||
|
Console.WriteLine("Restarting in 5 seconds.");
|
||||||
|
Thread.Sleep(5000);
|
||||||
var exe = typeof(Program).Assembly.Location;
|
var exe = typeof(Program).Assembly.Location;
|
||||||
_config.WaitForPID = Process.GetCurrentProcess().Id.ToString();
|
_config.WaitForPID = Process.GetCurrentProcess().Id.ToString();
|
||||||
Process.Start(exe, _config.ToString());
|
Process.Start(exe, _config.ToString());
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
MessageBox.Show("Torch encountered a fatal error and needs to close. Please check the logs for details.");
|
||||||
|
}
|
||||||
|
|
||||||
Process.GetCurrentProcess().Kill();
|
Process.GetCurrentProcess().Kill();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -10,19 +10,27 @@ using Havok;
|
|||||||
using NLog;
|
using NLog;
|
||||||
using Sandbox.Engine.Networking;
|
using Sandbox.Engine.Networking;
|
||||||
using Sandbox.Engine.Utils;
|
using Sandbox.Engine.Utils;
|
||||||
|
using Sandbox.Game;
|
||||||
|
using Sandbox.Game.Gui;
|
||||||
using Torch.API;
|
using Torch.API;
|
||||||
using Torch.API.Managers;
|
using Torch.API.Managers;
|
||||||
using Torch.Managers;
|
using Torch.Managers;
|
||||||
|
using Torch.Mod;
|
||||||
using Torch.Server.ViewModels;
|
using Torch.Server.ViewModels;
|
||||||
|
using VRage;
|
||||||
using VRage.FileSystem;
|
using VRage.FileSystem;
|
||||||
using VRage.Game;
|
using VRage.Game;
|
||||||
|
using VRage.Game.ObjectBuilder;
|
||||||
using VRage.ObjectBuilders;
|
using VRage.ObjectBuilders;
|
||||||
|
using VRage.Plugins;
|
||||||
|
|
||||||
namespace Torch.Server.Managers
|
namespace Torch.Server.Managers
|
||||||
{
|
{
|
||||||
public class InstanceManager : Manager
|
public class InstanceManager : Manager
|
||||||
{
|
{
|
||||||
private const string CONFIG_NAME = "SpaceEngineers-Dedicated.cfg";
|
private const string CONFIG_NAME = "SpaceEngineers-Dedicated.cfg";
|
||||||
|
|
||||||
|
public event Action<ConfigDedicatedViewModel> InstanceLoaded;
|
||||||
public ConfigDedicatedViewModel DedicatedConfig { get; set; }
|
public ConfigDedicatedViewModel DedicatedConfig { get; set; }
|
||||||
private static readonly Logger Log = LogManager.GetLogger(nameof(InstanceManager));
|
private static readonly Logger Log = LogManager.GetLogger(nameof(InstanceManager));
|
||||||
[Dependency]
|
[Dependency]
|
||||||
@@ -35,6 +43,8 @@ namespace Torch.Server.Managers
|
|||||||
|
|
||||||
public void LoadInstance(string path, bool validate = true)
|
public void LoadInstance(string path, bool validate = true)
|
||||||
{
|
{
|
||||||
|
Log.Info($"Loading instance {path}");
|
||||||
|
|
||||||
if (validate)
|
if (validate)
|
||||||
ValidateInstance(path);
|
ValidateInstance(path);
|
||||||
|
|
||||||
@@ -54,33 +64,73 @@ namespace Torch.Server.Managers
|
|||||||
config.Load(configPath);
|
config.Load(configPath);
|
||||||
|
|
||||||
DedicatedConfig = new ConfigDedicatedViewModel(config);
|
DedicatedConfig = new ConfigDedicatedViewModel(config);
|
||||||
|
|
||||||
var worldFolders = Directory.EnumerateDirectories(Path.Combine(Torch.Config.InstancePath, "Saves"));
|
var worldFolders = Directory.EnumerateDirectories(Path.Combine(Torch.Config.InstancePath, "Saves"));
|
||||||
|
|
||||||
foreach (var f in worldFolders)
|
foreach (var f in worldFolders)
|
||||||
DedicatedConfig.WorldPaths.Add(f);
|
{
|
||||||
|
if (!string.IsNullOrEmpty(f) && File.Exists(Path.Combine(f, "Sandbox.sbc")))
|
||||||
|
DedicatedConfig.Worlds.Add(new WorldViewModel(f));
|
||||||
|
}
|
||||||
|
|
||||||
if (DedicatedConfig.WorldPaths.Count == 0)
|
if (DedicatedConfig.Worlds.Count == 0)
|
||||||
{
|
{
|
||||||
Log.Warn($"No worlds found in the current instance {path}.");
|
Log.Warn($"No worlds found in the current instance {path}.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ImportWorldConfig();
|
SelectWorld(DedicatedConfig.LoadWorld ?? DedicatedConfig.Worlds.First().WorldPath, false);
|
||||||
|
|
||||||
/*
|
InstanceLoaded?.Invoke(DedicatedConfig);
|
||||||
if (string.IsNullOrEmpty(DedicatedConfig.LoadWorld))
|
|
||||||
{
|
|
||||||
Log.Warn("No world specified, importing first available world.");
|
|
||||||
SelectWorld(DedicatedConfig.WorldPaths[0], false);
|
|
||||||
}*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SelectWorld(string worldPath, bool modsOnly = true)
|
public void SelectWorld(string worldPath, bool modsOnly = true)
|
||||||
{
|
{
|
||||||
DedicatedConfig.LoadWorld = worldPath;
|
DedicatedConfig.LoadWorld = worldPath;
|
||||||
ImportWorldConfig(modsOnly);
|
DedicatedConfig.SelectedWorld = DedicatedConfig.Worlds.FirstOrDefault(x => x.WorldPath == worldPath);
|
||||||
|
if (DedicatedConfig.SelectedWorld?.Checkpoint != null)
|
||||||
|
{
|
||||||
|
DedicatedConfig.Mods.Clear();
|
||||||
|
//remove the Torch mod to avoid running multiple copies of it
|
||||||
|
DedicatedConfig.SelectedWorld.Checkpoint.Mods.RemoveAll(m => m.PublishedFileId == TorchModCore.MOD_ID);
|
||||||
|
foreach (var m in DedicatedConfig.SelectedWorld.Checkpoint.Mods)
|
||||||
|
DedicatedConfig.Mods.Add(m.PublishedFileId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SelectWorld(WorldViewModel world, bool modsOnly = true)
|
||||||
|
{
|
||||||
|
DedicatedConfig.LoadWorld = world.WorldPath;
|
||||||
|
DedicatedConfig.SelectedWorld = world;
|
||||||
|
if (DedicatedConfig.SelectedWorld?.Checkpoint != null)
|
||||||
|
{
|
||||||
|
DedicatedConfig.Mods.Clear();
|
||||||
|
//remove the Torch mod to avoid running multiple copies of it
|
||||||
|
DedicatedConfig.SelectedWorld.Checkpoint.Mods.RemoveAll(m => m.PublishedFileId == TorchModCore.MOD_ID);
|
||||||
|
foreach (var m in DedicatedConfig.SelectedWorld.Checkpoint.Mods)
|
||||||
|
DedicatedConfig.Mods.Add(m.PublishedFileId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ImportSelectedWorldConfig()
|
||||||
|
{
|
||||||
|
ImportWorldConfig(DedicatedConfig.SelectedWorld, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ImportWorldConfig(WorldViewModel world, bool modsOnly = true)
|
||||||
|
{
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
foreach (var mod in world.Checkpoint.Mods)
|
||||||
|
sb.AppendLine(mod.PublishedFileId.ToString());
|
||||||
|
|
||||||
|
DedicatedConfig.Mods = world.Checkpoint.Mods.Select(x => x.PublishedFileId).ToList();
|
||||||
|
|
||||||
|
|
||||||
|
Log.Debug("Loaded mod list from world");
|
||||||
|
|
||||||
|
if (!modsOnly)
|
||||||
|
DedicatedConfig.SessionSettings = world.Checkpoint.Settings;
|
||||||
|
}
|
||||||
|
|
||||||
private void ImportWorldConfig(bool modsOnly = true)
|
private void ImportWorldConfig(bool modsOnly = true)
|
||||||
{
|
{
|
||||||
@@ -97,15 +147,11 @@ namespace Torch.Server.Managers
|
|||||||
MyObjectBuilderSerializer.DeserializeXML(sandboxPath, out MyObjectBuilder_Checkpoint checkpoint, out ulong sizeInBytes);
|
MyObjectBuilderSerializer.DeserializeXML(sandboxPath, out MyObjectBuilder_Checkpoint checkpoint, out ulong sizeInBytes);
|
||||||
if (checkpoint == null)
|
if (checkpoint == null)
|
||||||
{
|
{
|
||||||
Log.Error($"Failed to load {DedicatedConfig.LoadWorld}, checkpoint null ({sizeInBytes} bytes, instance {TorchBase.Instance.Config.InstancePath})");
|
Log.Error($"Failed to load {DedicatedConfig.LoadWorld}, checkpoint null ({sizeInBytes} bytes, instance {Torch.Config.InstancePath})");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var sb = new StringBuilder();
|
DedicatedConfig.Mods = checkpoint.Mods.Select(x => x.PublishedFileId).ToList();
|
||||||
foreach (var mod in checkpoint.Mods)
|
|
||||||
sb.AppendLine(mod.PublishedFileId.ToString());
|
|
||||||
|
|
||||||
DedicatedConfig.Mods = sb.ToString();
|
|
||||||
|
|
||||||
Log.Debug("Loaded mod list from world");
|
Log.Debug("Loaded mod list from world");
|
||||||
|
|
||||||
@@ -121,23 +167,39 @@ namespace Torch.Server.Managers
|
|||||||
|
|
||||||
public void SaveConfig()
|
public void SaveConfig()
|
||||||
{
|
{
|
||||||
|
var cf = Torch.Config as TorchConfig;
|
||||||
|
if (cf?.ReservedPlayers?.Count > 0)
|
||||||
|
{
|
||||||
|
foreach (var res in cf.ReservedPlayers)
|
||||||
|
{
|
||||||
|
if (!DedicatedConfig.Reserved.Contains(res))
|
||||||
|
DedicatedConfig.Reserved.Add(res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
DedicatedConfig.Save(Path.Combine(Torch.Config.InstancePath, CONFIG_NAME));
|
DedicatedConfig.Save(Path.Combine(Torch.Config.InstancePath, CONFIG_NAME));
|
||||||
Log.Info("Saved dedicated config.");
|
Log.Info("Saved dedicated config.");
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
MyObjectBuilderSerializer.DeserializeXML(Path.Combine(DedicatedConfig.LoadWorld, "Sandbox.sbc"), out MyObjectBuilder_Checkpoint checkpoint, out ulong sizeInBytes);
|
var sandboxPath = Path.Combine(DedicatedConfig.LoadWorld, "Sandbox.sbc");
|
||||||
|
MyObjectBuilderSerializer.DeserializeXML(sandboxPath, out MyObjectBuilder_Checkpoint checkpoint, out ulong sizeInBytes);
|
||||||
if (checkpoint == null)
|
if (checkpoint == null)
|
||||||
{
|
{
|
||||||
Log.Error($"Failed to load {DedicatedConfig.LoadWorld}, checkpoint null ({sizeInBytes} bytes, instance {TorchBase.Instance.Config.InstancePath})");
|
Log.Error($"Failed to load {DedicatedConfig.LoadWorld}, checkpoint null ({sizeInBytes} bytes, instance {Torch.Config.InstancePath})");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
checkpoint.SessionName = DedicatedConfig.WorldName;
|
||||||
checkpoint.Settings = DedicatedConfig.SessionSettings;
|
checkpoint.Settings = DedicatedConfig.SessionSettings;
|
||||||
checkpoint.Mods.Clear();
|
checkpoint.Mods.Clear();
|
||||||
foreach (var modId in DedicatedConfig.Model.Mods)
|
|
||||||
|
foreach (var modId in DedicatedConfig.Mods)
|
||||||
checkpoint.Mods.Add(new MyObjectBuilder_Checkpoint.ModItem(modId));
|
checkpoint.Mods.Add(new MyObjectBuilder_Checkpoint.ModItem(modId));
|
||||||
|
|
||||||
MyLocalCache.SaveCheckpoint(checkpoint, DedicatedConfig.LoadWorld);
|
MyObjectBuilderSerializer.SerializeXML(sandboxPath, false, checkpoint);
|
||||||
|
|
||||||
|
//MyLocalCache.SaveCheckpoint(checkpoint, DedicatedConfig.LoadWorld);
|
||||||
Log.Info("Saved world config.");
|
Log.Info("Saved world config.");
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
@@ -162,4 +224,44 @@ namespace Torch.Server.Managers
|
|||||||
config.Save(configPath);
|
config.Save(configPath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class WorldViewModel : ViewModel
|
||||||
|
{
|
||||||
|
private static readonly Logger Log = LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
|
public string FolderName { get; set; }
|
||||||
|
public string WorldPath { get; }
|
||||||
|
public long WorldSizeKB { get; }
|
||||||
|
private string _checkpointPath;
|
||||||
|
public CheckpointViewModel Checkpoint { get; private set; }
|
||||||
|
|
||||||
|
public WorldViewModel(string worldPath)
|
||||||
|
{
|
||||||
|
WorldPath = worldPath;
|
||||||
|
WorldSizeKB = new DirectoryInfo(worldPath).GetFiles().Sum(x => x.Length) / 1024;
|
||||||
|
_checkpointPath = Path.Combine(WorldPath, "Sandbox.sbc");
|
||||||
|
FolderName = Path.GetFileName(worldPath);
|
||||||
|
BeginLoadCheckpoint();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task SaveCheckpointAsync()
|
||||||
|
{
|
||||||
|
await Task.Run(() =>
|
||||||
|
{
|
||||||
|
using (var f = File.Open(_checkpointPath, FileMode.Create))
|
||||||
|
MyObjectBuilderSerializer.SerializeXML(f, Checkpoint);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void BeginLoadCheckpoint()
|
||||||
|
{
|
||||||
|
//Task.Run(() =>
|
||||||
|
{
|
||||||
|
Log.Info($"Preloading checkpoint {_checkpointPath}");
|
||||||
|
MyObjectBuilderSerializer.DeserializeXML(_checkpointPath, out MyObjectBuilder_Checkpoint checkpoint);
|
||||||
|
Checkpoint = new CheckpointViewModel(checkpoint);
|
||||||
|
OnPropertyChanged(nameof(Checkpoint));
|
||||||
|
}//);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@@ -9,11 +10,15 @@ using NLog.Fluent;
|
|||||||
using Sandbox;
|
using Sandbox;
|
||||||
using Sandbox.Engine.Multiplayer;
|
using Sandbox.Engine.Multiplayer;
|
||||||
using Sandbox.Engine.Networking;
|
using Sandbox.Engine.Networking;
|
||||||
|
using Sandbox.Game.World;
|
||||||
|
using Steamworks;
|
||||||
using Torch.API;
|
using Torch.API;
|
||||||
using Torch.API.Managers;
|
using Torch.API.Managers;
|
||||||
using Torch.Managers;
|
using Torch.Managers;
|
||||||
using Torch.Utils;
|
using Torch.Utils;
|
||||||
using Torch.ViewModels;
|
using Torch.ViewModels;
|
||||||
|
using VRage.Game;
|
||||||
|
using VRage.Game.ModAPI;
|
||||||
using VRage.GameServices;
|
using VRage.GameServices;
|
||||||
using VRage.Network;
|
using VRage.Network;
|
||||||
using VRage.Steam;
|
using VRage.Steam;
|
||||||
@@ -25,7 +30,9 @@ namespace Torch.Server.Managers
|
|||||||
private static readonly Logger _log = LogManager.GetCurrentClassLogger();
|
private static readonly Logger _log = LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
#pragma warning disable 649
|
#pragma warning disable 649
|
||||||
[ReflectedGetter(Name = "m_members")] private static Func<MyDedicatedServerBase, List<ulong>> _members;
|
[ReflectedGetter(Name = "m_members")]
|
||||||
|
private static Func<MyDedicatedServerBase, List<ulong>> _members;
|
||||||
|
|
||||||
[ReflectedGetter(Name = "m_waitingForGroup")]
|
[ReflectedGetter(Name = "m_waitingForGroup")]
|
||||||
private static Func<MyDedicatedServerBase, HashSet<ulong>> _waitingForGroup;
|
private static Func<MyDedicatedServerBase, HashSet<ulong>> _waitingForGroup;
|
||||||
#pragma warning restore 649
|
#pragma warning restore 649
|
||||||
@@ -35,6 +42,9 @@ namespace Torch.Server.Managers
|
|||||||
|
|
||||||
private Dictionary<ulong, ulong> _gameOwnerIds = new Dictionary<ulong, ulong>();
|
private Dictionary<ulong, ulong> _gameOwnerIds = new Dictionary<ulong, ulong>();
|
||||||
|
|
||||||
|
[Dependency]
|
||||||
|
private InstanceManager _instanceManager;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public MultiplayerManagerDedicated(ITorchBase torch) : base(torch)
|
public MultiplayerManagerDedicated(ITorchBase torch) : base(torch)
|
||||||
{
|
{
|
||||||
@@ -49,15 +59,34 @@ namespace Torch.Server.Managers
|
|||||||
Torch.Invoke(() =>
|
Torch.Invoke(() =>
|
||||||
{
|
{
|
||||||
MyMultiplayer.Static.BanClient(steamId, banned);
|
MyMultiplayer.Static.BanClient(steamId, banned);
|
||||||
if (_gameOwnerIds.ContainsKey(steamId))
|
|
||||||
MyMultiplayer.Static.BanClient(_gameOwnerIds[steamId], banned);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal void RaiseClientBanned(ulong user, bool banned)
|
||||||
|
{
|
||||||
|
PlayerBanned?.Invoke(user, banned);
|
||||||
|
Torch.Invoke(() =>
|
||||||
|
{
|
||||||
|
if(_gameOwnerIds.TryGetValue(user, out ulong owner))
|
||||||
|
MyMultiplayer.Static.BanClient(owner, banned);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void RaiseClientKicked(ulong user)
|
||||||
|
{
|
||||||
|
PlayerKicked?.Invoke(user);
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public bool IsBanned(ulong steamId) => _isClientBanned.Invoke(MyMultiplayer.Static, steamId) ||
|
public bool IsBanned(ulong steamId) => _isClientBanned.Invoke(MyMultiplayer.Static, steamId) ||
|
||||||
MySandboxGame.ConfigDedicated.Banned.Contains(steamId);
|
MySandboxGame.ConfigDedicated.Banned.Contains(steamId);
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public event Action<ulong> PlayerKicked;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public event Action<ulong, bool> PlayerBanned;
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public override void Attach()
|
public override void Attach()
|
||||||
{
|
{
|
||||||
@@ -105,13 +134,17 @@ namespace Torch.Server.Managers
|
|||||||
[ReflectedStaticMethod(Type = typeof(MyGameService), Name = "GetServerAccountType")]
|
[ReflectedStaticMethod(Type = typeof(MyGameService), Name = "GetServerAccountType")]
|
||||||
private static Func<ulong, MyGameServiceAccountType> _getServerAccountType;
|
private static Func<ulong, MyGameServiceAccountType> _getServerAccountType;
|
||||||
|
|
||||||
[ReflectedMethod(Name = "UserAccepted")] private static Action<MyDedicatedServerBase, ulong> _userAcceptedImpl;
|
[ReflectedMethod(Name = "UserAccepted")]
|
||||||
|
private static Action<MyDedicatedServerBase, ulong> _userAcceptedImpl;
|
||||||
|
|
||||||
[ReflectedMethod(Name = "UserRejected")]
|
[ReflectedMethod(Name = "UserRejected")]
|
||||||
private static Action<MyDedicatedServerBase, ulong, JoinResult> _userRejected;
|
private static Action<MyDedicatedServerBase, ulong, JoinResult> _userRejected;
|
||||||
|
|
||||||
[ReflectedMethod(Name = "IsClientBanned")] private static Func<MyMultiplayerBase, ulong, bool> _isClientBanned;
|
[ReflectedMethod(Name = "IsClientBanned")]
|
||||||
[ReflectedMethod(Name = "IsClientKicked")] private static Func<MyMultiplayerBase, ulong, bool> _isClientKicked;
|
private static Func<MyMultiplayerBase, ulong, bool> _isClientBanned;
|
||||||
|
|
||||||
|
[ReflectedMethod(Name = "IsClientKicked")]
|
||||||
|
private static Func<MyMultiplayerBase, ulong, bool> _isClientKicked;
|
||||||
|
|
||||||
[ReflectedMethod(Name = "RaiseClientKicked")]
|
[ReflectedMethod(Name = "RaiseClientKicked")]
|
||||||
private static Action<MyMultiplayerBase, ulong> _raiseClientKicked;
|
private static Action<MyMultiplayerBase, ulong> _raiseClientKicked;
|
||||||
@@ -135,50 +168,83 @@ namespace Torch.Server.Managers
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Largely copied from SE
|
//Largely copied from SE
|
||||||
private void ValidateAuthTicketResponse(ulong steamID, JoinResult response, ulong steamOwner)
|
private void ValidateAuthTicketResponse(ulong steamId, JoinResult response, ulong steamOwner)
|
||||||
{
|
{
|
||||||
_log.Debug($"ValidateAuthTicketResponse(user={steamID}, response={response}, owner={steamOwner}");
|
var state = new MyP2PSessionState();
|
||||||
if (MySandboxGame.ConfigDedicated.GroupID == 0uL)
|
MySteamService.Static.Peer2Peer.GetSessionState(steamId, ref state);
|
||||||
RunEvent(new ValidateAuthTicketEvent(steamID, steamOwner, response, 0, true, false));
|
var ip = new IPAddress(BitConverter.GetBytes(state.RemoteIP).Reverse().ToArray());
|
||||||
|
|
||||||
|
Torch.CurrentSession.KeenSession.PromotedUsers.TryGetValue(steamId, out MyPromoteLevel promoteLevel);
|
||||||
|
|
||||||
|
_log.Debug($"ValidateAuthTicketResponse(user={steamId}, response={response}, owner={steamOwner}, permissions={promoteLevel})");
|
||||||
|
|
||||||
|
_log.Info($"Connection attempt by {steamId} from {ip}");
|
||||||
|
|
||||||
|
if (Torch.CurrentSession.KeenSession.OnlineMode == MyOnlineModeEnum.OFFLINE &&
|
||||||
|
promoteLevel < MyPromoteLevel.Admin)
|
||||||
|
{
|
||||||
|
_log.Warn($"Rejecting user {steamId}, world is set to offline and user is not admin.");
|
||||||
|
UserRejected(steamId, JoinResult.TicketCanceled);
|
||||||
|
}
|
||||||
|
else if (MySandboxGame.ConfigDedicated.GroupID == 0uL)
|
||||||
|
RunEvent(new ValidateAuthTicketEvent(steamId, steamOwner, response, 0, true, false));
|
||||||
else if (_getServerAccountType(MySandboxGame.ConfigDedicated.GroupID) != MyGameServiceAccountType.Clan)
|
else if (_getServerAccountType(MySandboxGame.ConfigDedicated.GroupID) != MyGameServiceAccountType.Clan)
|
||||||
UserRejected(steamID, JoinResult.GroupIdInvalid);
|
UserRejected(steamId, JoinResult.GroupIdInvalid);
|
||||||
else if (MyGameService.GameServer.RequestGroupStatus(steamID, MySandboxGame.ConfigDedicated.GroupID))
|
else if (MyGameService.GameServer.RequestGroupStatus(steamId, MySandboxGame.ConfigDedicated.GroupID))
|
||||||
lock (_waitingForGroupLocal)
|
lock (_waitingForGroupLocal)
|
||||||
{
|
{
|
||||||
if (_waitingForGroupLocal.Count >= _waitListSize)
|
if (_waitingForGroupLocal.Count >= _waitListSize)
|
||||||
_waitingForGroupLocal.RemoveAt(0);
|
_waitingForGroupLocal.RemoveAt(0);
|
||||||
_waitingForGroupLocal.Add(new WaitingForGroup(steamID, response, steamOwner));
|
_waitingForGroupLocal.Add(new WaitingForGroup(steamId, response, steamOwner));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
UserRejected(steamID, JoinResult.SteamServersOffline);
|
UserRejected(steamId, JoinResult.SteamServersOffline);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RunEvent(ValidateAuthTicketEvent info)
|
private void RunEvent(ValidateAuthTicketEvent info)
|
||||||
{
|
{
|
||||||
MultiplayerManagerDedicatedEventShim.RaiseValidateAuthTicket(ref info);
|
JoinResult internalAuth;
|
||||||
|
|
||||||
if (info.FutureVerdict == null)
|
|
||||||
|
if (IsBanned(info.SteamOwner) || IsBanned(info.SteamID))
|
||||||
|
internalAuth = JoinResult.BannedByAdmins;
|
||||||
|
else if (_isClientKicked(MyMultiplayer.Static, info.SteamID) ||
|
||||||
|
_isClientKicked(MyMultiplayer.Static, info.SteamOwner))
|
||||||
|
internalAuth = JoinResult.KickedRecently;
|
||||||
|
else if (info.SteamResponse == JoinResult.OK)
|
||||||
{
|
{
|
||||||
if (IsBanned(info.SteamOwner) || IsBanned(info.SteamID))
|
var config = (TorchConfig) Torch.Config;
|
||||||
CommitVerdict(info.SteamID, JoinResult.BannedByAdmins);
|
if (config.EnableWhitelist && !config.Whitelist.Contains(info.SteamID))
|
||||||
else if (_isClientKicked(MyMultiplayer.Static, info.SteamID) ||
|
{
|
||||||
_isClientKicked(MyMultiplayer.Static, info.SteamOwner))
|
_log.Warn($"Rejecting user {info.SteamID} because they are not whitelisted in Torch.cfg.");
|
||||||
CommitVerdict(info.SteamID, JoinResult.KickedRecently);
|
internalAuth = JoinResult.NotInGroup;
|
||||||
else if (info.SteamResponse != JoinResult.OK)
|
}
|
||||||
CommitVerdict(info.SteamID, info.SteamResponse);
|
else if (MySandboxGame.ConfigDedicated.Reserved.Contains(info.SteamID))
|
||||||
else if (MyMultiplayer.Static.MemberLimit > 0 &&
|
internalAuth = JoinResult.OK;
|
||||||
MyMultiplayer.Static.MemberCount + 1 > MyMultiplayer.Static.MemberLimit)
|
//Admins can bypass member limit
|
||||||
CommitVerdict(info.SteamID, JoinResult.ServerFull);
|
else if (MySandboxGame.ConfigDedicated.Administrators.Contains(info.SteamID.ToString()) ||
|
||||||
else if (MySandboxGame.ConfigDedicated.GroupID == 0uL ||
|
|
||||||
MySandboxGame.ConfigDedicated.Administrators.Contains(info.SteamID.ToString()) ||
|
|
||||||
MySandboxGame.ConfigDedicated.Administrators.Contains(_convertSteamIDFrom64(info.SteamID)))
|
MySandboxGame.ConfigDedicated.Administrators.Contains(_convertSteamIDFrom64(info.SteamID)))
|
||||||
CommitVerdict(info.SteamID, JoinResult.OK);
|
internalAuth = JoinResult.OK;
|
||||||
else if (MySandboxGame.ConfigDedicated.GroupID == info.Group && (info.Member || info.Officer))
|
//Server counts as a client, so subtract 1 from MemberCount
|
||||||
CommitVerdict(info.SteamID, JoinResult.OK);
|
else if (MyMultiplayer.Static.MemberLimit > 0 &&
|
||||||
|
MyMultiplayer.Static.MemberCount - 1 >= MyMultiplayer.Static.MemberLimit)
|
||||||
|
internalAuth = JoinResult.ServerFull;
|
||||||
|
else if (MySandboxGame.ConfigDedicated.GroupID == 0uL)
|
||||||
|
internalAuth = JoinResult.OK;
|
||||||
else
|
else
|
||||||
CommitVerdict(info.SteamID, JoinResult.NotInGroup);
|
{
|
||||||
return;
|
if (MySandboxGame.ConfigDedicated.GroupID == info.Group && (info.Member || info.Officer))
|
||||||
|
internalAuth = JoinResult.OK;
|
||||||
|
else
|
||||||
|
internalAuth = JoinResult.NotInGroup;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
internalAuth = info.SteamResponse;
|
||||||
|
|
||||||
|
info.FutureVerdict = Task.FromResult(internalAuth);
|
||||||
|
|
||||||
|
MultiplayerManagerDedicatedEventShim.RaiseValidateAuthTicket(ref info);
|
||||||
|
|
||||||
info.FutureVerdict.ContinueWith((task) =>
|
info.FutureVerdict.ContinueWith((task) =>
|
||||||
{
|
{
|
||||||
@@ -190,6 +256,7 @@ namespace Torch.Server.Managers
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
verdict = task.Result;
|
verdict = task.Result;
|
||||||
|
|
||||||
Torch.Invoke(() => { CommitVerdict(info.SteamID, verdict); });
|
Torch.Invoke(() => { CommitVerdict(info.SteamID, verdict); });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,32 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using NLog;
|
||||||
|
using Sandbox.Engine.Multiplayer;
|
||||||
|
using Torch.Managers.PatchManager;
|
||||||
|
using Torch.API.Managers;
|
||||||
|
|
||||||
|
namespace Torch.Server.Managers
|
||||||
|
{
|
||||||
|
[PatchShim]
|
||||||
|
internal static class MultiplayerManagerDedicatedPatchShim
|
||||||
|
{
|
||||||
|
public static void Patch(PatchContext ctx)
|
||||||
|
{
|
||||||
|
ctx.GetPattern(typeof(MyDedicatedServerBase).GetMethod(nameof(MyDedicatedServerBase.BanClient))).Prefixes.Add(typeof(MultiplayerManagerDedicatedPatchShim).GetMethod(nameof(BanPrefix)));
|
||||||
|
ctx.GetPattern(typeof(MyDedicatedServerBase).GetMethod(nameof(MyDedicatedServerBase.KickClient))).Prefixes.Add(typeof(MultiplayerManagerDedicatedPatchShim).GetMethod(nameof(KickPrefix)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void BanPrefix(ulong userId, bool banned)
|
||||||
|
{
|
||||||
|
TorchBase.Instance.CurrentSession.Managers.GetManager<MultiplayerManagerDedicated>().RaiseClientBanned(userId, banned);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void KickPrefix(ulong userId)
|
||||||
|
{
|
||||||
|
TorchBase.Instance.CurrentSession.Managers.GetManager<MultiplayerManagerDedicated>().RaiseClientKicked(userId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
49
Torch.Server/MultiTextWriter.cs
Normal file
49
Torch.Server/MultiTextWriter.cs
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Torch.Server
|
||||||
|
{
|
||||||
|
public class MultiTextWriter : TextWriter
|
||||||
|
{
|
||||||
|
private IEnumerable<TextWriter> writers;
|
||||||
|
public MultiTextWriter(IEnumerable<TextWriter> writers)
|
||||||
|
{
|
||||||
|
this.writers = writers.ToList();
|
||||||
|
}
|
||||||
|
public MultiTextWriter(params TextWriter[] writers)
|
||||||
|
{
|
||||||
|
this.writers = writers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Write(char value)
|
||||||
|
{
|
||||||
|
foreach (var writer in writers)
|
||||||
|
writer.Write(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Write(string value)
|
||||||
|
{
|
||||||
|
foreach (var writer in writers)
|
||||||
|
writer.Write(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Flush()
|
||||||
|
{
|
||||||
|
foreach (var writer in writers)
|
||||||
|
writer.Flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Close()
|
||||||
|
{
|
||||||
|
foreach (var writer in writers)
|
||||||
|
writer.Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Encoding Encoding
|
||||||
|
{
|
||||||
|
get { return Encoding.ASCII; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -1,33 +1,15 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Configuration.Install;
|
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.IO.Compression;
|
||||||
|
using System.Net;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.ServiceProcess;
|
using System.ServiceProcess;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Windows;
|
|
||||||
using System.Windows.Threading;
|
|
||||||
using Microsoft.CodeAnalysis;
|
|
||||||
using Microsoft.CodeAnalysis.CSharp;
|
|
||||||
using NLog;
|
using NLog;
|
||||||
using Sandbox.Game.World;
|
using NLog.Targets;
|
||||||
using Sandbox.ModAPI;
|
|
||||||
using Torch;
|
|
||||||
using Torch.API;
|
|
||||||
using Torch.Server.Views;
|
|
||||||
using VRage.Game.ModAPI;
|
|
||||||
using System.IO.Compression;
|
|
||||||
using System.Net;
|
|
||||||
using System.Security.Policy;
|
|
||||||
using Torch.Server.Managers;
|
|
||||||
using Torch.Utils;
|
using Torch.Utils;
|
||||||
using VRage.FileSystem;
|
|
||||||
using VRageRender;
|
|
||||||
|
|
||||||
namespace Torch.Server
|
namespace Torch.Server
|
||||||
{
|
{
|
||||||
@@ -39,6 +21,7 @@ namespace Torch.Server
|
|||||||
[STAThread]
|
[STAThread]
|
||||||
public static void Main(string[] args)
|
public static void Main(string[] args)
|
||||||
{
|
{
|
||||||
|
Target.Register<FlowDocumentTarget>("FlowDocument");
|
||||||
//Ensures that all the files are downloaded in the Torch directory.
|
//Ensures that all the files are downloaded in the Torch directory.
|
||||||
var workingDir = new FileInfo(typeof(Program).Assembly.Location).Directory.ToString();
|
var workingDir = new FileInfo(typeof(Program).Assembly.Location).Directory.ToString();
|
||||||
var binDir = Path.Combine(workingDir, "DedicatedServer64");
|
var binDir = Path.Combine(workingDir, "DedicatedServer64");
|
||||||
@@ -46,7 +29,7 @@ namespace Torch.Server
|
|||||||
|
|
||||||
if (!TorchLauncher.IsTorchWrapped())
|
if (!TorchLauncher.IsTorchWrapped())
|
||||||
{
|
{
|
||||||
TorchLauncher.Launch(Assembly.GetEntryAssembly().FullName,args, binDir);
|
TorchLauncher.Launch(Assembly.GetEntryAssembly().FullName, args, binDir);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
1065
Torch.Server/Properties/Annotations.cs
Normal file
1065
Torch.Server/Properties/Annotations.cs
Normal file
File diff suppressed because it is too large
Load Diff
89
Torch.Server/RichTextBoxWriter.cs
Normal file
89
Torch.Server/RichTextBoxWriter.cs
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
using System.Windows.Documents;
|
||||||
|
using System.Windows.Media;
|
||||||
|
|
||||||
|
namespace Torch.Server
|
||||||
|
{
|
||||||
|
public class RichTextBoxWriter : TextWriter
|
||||||
|
{
|
||||||
|
private RichTextBox textbox;
|
||||||
|
private StringBuilder _cache = new StringBuilder();
|
||||||
|
public RichTextBoxWriter(RichTextBox textbox)
|
||||||
|
{
|
||||||
|
this.textbox = textbox;
|
||||||
|
textbox.Document.Background = new SolidColorBrush(UnpackColor(Console.BackgroundColor));
|
||||||
|
textbox.Document.Blocks.Clear();
|
||||||
|
textbox.Document.Blocks.Add(new Paragraph {LineHeight = 12});
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Write(char value)
|
||||||
|
{
|
||||||
|
if (value == '\r')
|
||||||
|
return;
|
||||||
|
|
||||||
|
_cache.Append(value);
|
||||||
|
if (value == '\n')
|
||||||
|
{
|
||||||
|
var str = _cache.ToString();
|
||||||
|
_cache.Clear();
|
||||||
|
|
||||||
|
var brush = _brushes[Console.ForegroundColor];
|
||||||
|
textbox.Dispatcher.BeginInvoke(() =>
|
||||||
|
{
|
||||||
|
var p = (Paragraph)textbox.Document.Blocks.FirstBlock;
|
||||||
|
p.Inlines.Add(new Run(str) { Foreground = brush });
|
||||||
|
textbox.ScrollToEnd();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Write(string value)
|
||||||
|
{
|
||||||
|
var brush = _brushes[Console.ForegroundColor];
|
||||||
|
textbox.Dispatcher.BeginInvoke(() =>
|
||||||
|
{
|
||||||
|
var p = (Paragraph)textbox.Document.Blocks.FirstBlock;
|
||||||
|
p.Inlines.Add(new Run(value) { Foreground = brush });
|
||||||
|
textbox.ScrollToEnd();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Encoding Encoding
|
||||||
|
{
|
||||||
|
get { return Encoding.ASCII; }
|
||||||
|
}
|
||||||
|
|
||||||
|
static RichTextBoxWriter()
|
||||||
|
{
|
||||||
|
foreach (var value in (ConsoleColor[])Enum.GetValues(typeof(ConsoleColor)))
|
||||||
|
{
|
||||||
|
_brushes.Add(value, new SolidColorBrush(UnpackColor(value)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Dictionary<ConsoleColor, SolidColorBrush> _brushes = new Dictionary<ConsoleColor, SolidColorBrush>();
|
||||||
|
|
||||||
|
private static Color UnpackColor(ConsoleColor color)
|
||||||
|
{
|
||||||
|
var colorByte = (byte)color;
|
||||||
|
var isBright = (colorByte & 0b1000) >> 3 > 0;
|
||||||
|
var brightness = isBright ? (byte)255 : (byte)128;
|
||||||
|
var red = (colorByte & 0b0100) >> 2;
|
||||||
|
var green = (colorByte & 0b0010) >> 1;
|
||||||
|
var blue = (colorByte & 0b0001);
|
||||||
|
|
||||||
|
return new Color
|
||||||
|
{
|
||||||
|
R = (byte)(brightness * red),
|
||||||
|
G = (byte)(brightness * green),
|
||||||
|
B = (byte)(brightness * blue),
|
||||||
|
A = 255
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -1,14 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Torch.Collections;
|
|
||||||
|
|
||||||
namespace Torch.Server
|
|
||||||
{
|
|
||||||
public class ServerStatistics
|
|
||||||
{
|
|
||||||
public RollingAverage SimSpeed { get; } = new RollingAverage(30);
|
|
||||||
}
|
|
||||||
}
|
|
17
Torch.Server/Themes/Dark Theme Animated.xaml
Normal file
17
Torch.Server/Themes/Dark Theme Animated.xaml
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||||
|
<ResourceDictionary.MergedDictionaries>
|
||||||
|
<!-- MahApps.Metro resource dictionaries. Make sure that all file names are Case Sensitive! -->
|
||||||
|
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.xaml" />
|
||||||
|
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Fonts.xaml" />
|
||||||
|
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Colors.xaml" />
|
||||||
|
<!-- Accent and AppTheme setting -->
|
||||||
|
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/Blue.xaml" />
|
||||||
|
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/BaseDark.xaml" />
|
||||||
|
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.AnimatedSingleRowTabControl.xaml" />
|
||||||
|
</ResourceDictionary.MergedDictionaries>
|
||||||
|
|
||||||
|
<Style TargetType="Hyperlink" x:Name="LegalshtuffLink">
|
||||||
|
<Setter Property="NavigateUri" Value="https://github.com/MahApps/MahApps.Metro/blob/develop/LICENSE" />
|
||||||
|
</Style>
|
||||||
|
</ResourceDictionary>
|
85
Torch.Server/Themes/Dark Theme.xaml
Normal file
85
Torch.Server/Themes/Dark Theme.xaml
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||||
|
|
||||||
|
<ResourceDictionary.MergedDictionaries>
|
||||||
|
<!-- MahApps.Metro resource dictionaries. Make sure that all file names are Case Sensitive! -->
|
||||||
|
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.xaml" />
|
||||||
|
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Fonts.xaml" />
|
||||||
|
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Colors.xaml" />
|
||||||
|
<!-- Accent and AppTheme setting -->
|
||||||
|
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/Blue.xaml" />
|
||||||
|
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/BaseDark.xaml" />
|
||||||
|
</ResourceDictionary.MergedDictionaries>
|
||||||
|
|
||||||
|
<Style TargetType="TabControl">
|
||||||
|
<Setter Property="Background" Value="Transparent"/>
|
||||||
|
<Setter Property="Template">
|
||||||
|
<Setter.Value>
|
||||||
|
<ControlTemplate TargetType="TabControl">
|
||||||
|
<Grid ClipToBounds="true" SnapsToDevicePixels="true" KeyboardNavigation.TabNavigation="Local">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition x:Name="ColumnDefinition0"/>
|
||||||
|
<ColumnDefinition x:Name="ColumnDefinition1" Width="0"/>
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition x:Name="RowDefinition0" Height="Auto"/>
|
||||||
|
<RowDefinition x:Name="RowDefinition1" Height="*"/>
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<StackPanel x:Name="HeaderPanel" Grid.Column="0" IsItemsHost="true" Margin="2,2,2,0" Grid.Row="0" KeyboardNavigation.TabIndex="1" Panel.ZIndex="1" Orientation="Horizontal"/>
|
||||||
|
<Border x:Name="ContentPanel" BorderBrush="Transparent" BorderThickness="{TemplateBinding BorderThickness}" Background="Transparent" Grid.Column="0" KeyboardNavigation.DirectionalNavigation="Contained" Grid.Row="1" KeyboardNavigation.TabIndex="2" KeyboardNavigation.TabNavigation="Local">
|
||||||
|
<ContentPresenter x:Name="PART_SelectedContentHost" ContentSource="SelectedContent" Margin="{TemplateBinding Padding}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
|
||||||
|
</Border>
|
||||||
|
|
||||||
|
<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Hidden">
|
||||||
|
<TabPanel x:Name="HeaderPanel2"
|
||||||
|
Panel.ZIndex ="1"
|
||||||
|
KeyboardNavigation.TabIndex="1"
|
||||||
|
Grid.Column="0"
|
||||||
|
Grid.Row="0"
|
||||||
|
Margin="2,2,2,0"
|
||||||
|
IsItemsHost="true"/>
|
||||||
|
</ScrollViewer>
|
||||||
|
</Grid>
|
||||||
|
<ControlTemplate.Triggers>
|
||||||
|
<Trigger Property="TabStripPlacement" Value="Bottom">
|
||||||
|
<Setter Property="Grid.Row" TargetName="HeaderPanel" Value="1"/>
|
||||||
|
<Setter Property="Grid.Row" TargetName="ContentPanel" Value="0"/>
|
||||||
|
<Setter Property="Height" TargetName="RowDefinition0" Value="*"/>
|
||||||
|
<Setter Property="Height" TargetName="RowDefinition1" Value="Auto"/>
|
||||||
|
<Setter Property="Margin" TargetName="HeaderPanel" Value="2,0,2,2"/>
|
||||||
|
</Trigger>
|
||||||
|
<Trigger Property="TabStripPlacement" Value="Left">
|
||||||
|
<Setter Property="Grid.Row" TargetName="HeaderPanel" Value="0"/>
|
||||||
|
<Setter Property="Grid.Row" TargetName="ContentPanel" Value="0"/>
|
||||||
|
<Setter Property="Grid.Column" TargetName="HeaderPanel" Value="0"/>
|
||||||
|
<Setter Property="Grid.Column" TargetName="ContentPanel" Value="1"/>
|
||||||
|
<Setter Property="Width" TargetName="ColumnDefinition0" Value="Auto"/>
|
||||||
|
<Setter Property="Width" TargetName="ColumnDefinition1" Value="*"/>
|
||||||
|
<Setter Property="Height" TargetName="RowDefinition0" Value="*"/>
|
||||||
|
<Setter Property="Height" TargetName="RowDefinition1" Value="0"/>
|
||||||
|
<Setter Property="Margin" TargetName="HeaderPanel" Value="2,2,0,2"/>
|
||||||
|
</Trigger>
|
||||||
|
<Trigger Property="TabStripPlacement" Value="Right">
|
||||||
|
<Setter Property="Grid.Row" TargetName="HeaderPanel" Value="0"/>
|
||||||
|
<Setter Property="Grid.Row" TargetName="ContentPanel" Value="0"/>
|
||||||
|
<Setter Property="Grid.Column" TargetName="HeaderPanel" Value="1"/>
|
||||||
|
<Setter Property="Grid.Column" TargetName="ContentPanel" Value="0"/>
|
||||||
|
<Setter Property="Width" TargetName="ColumnDefinition0" Value="*"/>
|
||||||
|
<Setter Property="Width" TargetName="ColumnDefinition1" Value="Auto"/>
|
||||||
|
<Setter Property="Height" TargetName="RowDefinition0" Value="*"/>
|
||||||
|
<Setter Property="Height" TargetName="RowDefinition1" Value="0"/>
|
||||||
|
<Setter Property="Margin" TargetName="HeaderPanel" Value="0,2,2,2"/>
|
||||||
|
</Trigger>
|
||||||
|
<Trigger Property="IsEnabled" Value="false">
|
||||||
|
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
|
||||||
|
</Trigger>
|
||||||
|
</ControlTemplate.Triggers>
|
||||||
|
</ControlTemplate>
|
||||||
|
</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<Style TargetType="Hyperlink" x:Name="LegalshtuffLink">
|
||||||
|
<Setter Property="NavigateUri" Value="https://github.com/MahApps/MahApps.Metro/blob/develop/LICENSE" />
|
||||||
|
</Style>
|
||||||
|
</ResourceDictionary>
|
19
Torch.Server/Themes/Light Theme Animated.xaml
Normal file
19
Torch.Server/Themes/Light Theme Animated.xaml
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||||
|
|
||||||
|
|
||||||
|
<ResourceDictionary.MergedDictionaries>
|
||||||
|
<!-- MahApps.Metro resource dictionaries. Make sure that all file names are Case Sensitive! -->
|
||||||
|
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.xaml" />
|
||||||
|
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Fonts.xaml" />
|
||||||
|
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Colors.xaml" />
|
||||||
|
<!-- Accent and AppTheme setting -->
|
||||||
|
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/Blue.xaml" />
|
||||||
|
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/BaseLight.xaml" />
|
||||||
|
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.AnimatedSingleRowTabControl.xaml" />
|
||||||
|
</ResourceDictionary.MergedDictionaries>
|
||||||
|
|
||||||
|
<Style TargetType="Hyperlink" x:Name="LegalshtuffLink">
|
||||||
|
<Setter Property="NavigateUri" Value="https://github.com/MahApps/MahApps.Metro/blob/develop/LICENSE" />
|
||||||
|
</Style>
|
||||||
|
</ResourceDictionary>
|
85
Torch.Server/Themes/Light Theme.xaml
Normal file
85
Torch.Server/Themes/Light Theme.xaml
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||||
|
|
||||||
|
<ResourceDictionary.MergedDictionaries>
|
||||||
|
<!-- MahApps.Metro resource dictionaries. Make sure that all file names are Case Sensitive! -->
|
||||||
|
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.xaml" />
|
||||||
|
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Fonts.xaml" />
|
||||||
|
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Colors.xaml" />
|
||||||
|
<!-- Accent and AppTheme setting -->
|
||||||
|
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/Blue.xaml" />
|
||||||
|
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/BaseLight.xaml" />
|
||||||
|
</ResourceDictionary.MergedDictionaries>
|
||||||
|
|
||||||
|
<Style TargetType="TabControl">
|
||||||
|
<Setter Property="Background" Value="Transparent"/>
|
||||||
|
<Setter Property="Template">
|
||||||
|
<Setter.Value>
|
||||||
|
<ControlTemplate TargetType="TabControl">
|
||||||
|
<Grid ClipToBounds="true" SnapsToDevicePixels="true" KeyboardNavigation.TabNavigation="Local">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition x:Name="ColumnDefinition0"/>
|
||||||
|
<ColumnDefinition x:Name="ColumnDefinition1" Width="0"/>
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition x:Name="RowDefinition0" Height="Auto"/>
|
||||||
|
<RowDefinition x:Name="RowDefinition1" Height="*"/>
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<StackPanel x:Name="HeaderPanel" Grid.Column="0" IsItemsHost="true" Margin="2,2,2,0" Grid.Row="0" KeyboardNavigation.TabIndex="1" Panel.ZIndex="1" Orientation="Horizontal"/>
|
||||||
|
<Border x:Name="ContentPanel" BorderBrush="Transparent" BorderThickness="{TemplateBinding BorderThickness}" Background="Transparent" Grid.Column="0" KeyboardNavigation.DirectionalNavigation="Contained" Grid.Row="1" KeyboardNavigation.TabIndex="2" KeyboardNavigation.TabNavigation="Local">
|
||||||
|
<ContentPresenter x:Name="PART_SelectedContentHost" ContentSource="SelectedContent" Margin="{TemplateBinding Padding}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
|
||||||
|
</Border>
|
||||||
|
|
||||||
|
<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Hidden">
|
||||||
|
<TabPanel x:Name="HeaderPanel2"
|
||||||
|
Panel.ZIndex ="1"
|
||||||
|
KeyboardNavigation.TabIndex="1"
|
||||||
|
Grid.Column="0"
|
||||||
|
Grid.Row="0"
|
||||||
|
Margin="2,2,2,0"
|
||||||
|
IsItemsHost="true"/>
|
||||||
|
</ScrollViewer>
|
||||||
|
</Grid>
|
||||||
|
<ControlTemplate.Triggers>
|
||||||
|
<Trigger Property="TabStripPlacement" Value="Bottom">
|
||||||
|
<Setter Property="Grid.Row" TargetName="HeaderPanel" Value="1"/>
|
||||||
|
<Setter Property="Grid.Row" TargetName="ContentPanel" Value="0"/>
|
||||||
|
<Setter Property="Height" TargetName="RowDefinition0" Value="*"/>
|
||||||
|
<Setter Property="Height" TargetName="RowDefinition1" Value="Auto"/>
|
||||||
|
<Setter Property="Margin" TargetName="HeaderPanel" Value="2,0,2,2"/>
|
||||||
|
</Trigger>
|
||||||
|
<Trigger Property="TabStripPlacement" Value="Left">
|
||||||
|
<Setter Property="Grid.Row" TargetName="HeaderPanel" Value="0"/>
|
||||||
|
<Setter Property="Grid.Row" TargetName="ContentPanel" Value="0"/>
|
||||||
|
<Setter Property="Grid.Column" TargetName="HeaderPanel" Value="0"/>
|
||||||
|
<Setter Property="Grid.Column" TargetName="ContentPanel" Value="1"/>
|
||||||
|
<Setter Property="Width" TargetName="ColumnDefinition0" Value="Auto"/>
|
||||||
|
<Setter Property="Width" TargetName="ColumnDefinition1" Value="*"/>
|
||||||
|
<Setter Property="Height" TargetName="RowDefinition0" Value="*"/>
|
||||||
|
<Setter Property="Height" TargetName="RowDefinition1" Value="0"/>
|
||||||
|
<Setter Property="Margin" TargetName="HeaderPanel" Value="2,2,0,2"/>
|
||||||
|
</Trigger>
|
||||||
|
<Trigger Property="TabStripPlacement" Value="Right">
|
||||||
|
<Setter Property="Grid.Row" TargetName="HeaderPanel" Value="0"/>
|
||||||
|
<Setter Property="Grid.Row" TargetName="ContentPanel" Value="0"/>
|
||||||
|
<Setter Property="Grid.Column" TargetName="HeaderPanel" Value="1"/>
|
||||||
|
<Setter Property="Grid.Column" TargetName="ContentPanel" Value="0"/>
|
||||||
|
<Setter Property="Width" TargetName="ColumnDefinition0" Value="*"/>
|
||||||
|
<Setter Property="Width" TargetName="ColumnDefinition1" Value="Auto"/>
|
||||||
|
<Setter Property="Height" TargetName="RowDefinition0" Value="*"/>
|
||||||
|
<Setter Property="Height" TargetName="RowDefinition1" Value="0"/>
|
||||||
|
<Setter Property="Margin" TargetName="HeaderPanel" Value="0,2,2,2"/>
|
||||||
|
</Trigger>
|
||||||
|
<Trigger Property="IsEnabled" Value="false">
|
||||||
|
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
|
||||||
|
</Trigger>
|
||||||
|
</ControlTemplate.Triggers>
|
||||||
|
</ControlTemplate>
|
||||||
|
</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<Style TargetType="Hyperlink" x:Name="LegalshtuffLink">
|
||||||
|
<Setter Property="NavigateUri" Value="https://github.com/MahApps/MahApps.Metro/blob/develop/LICENSE" />
|
||||||
|
</Style>
|
||||||
|
</ResourceDictionary>
|
@@ -15,6 +15,21 @@
|
|||||||
<TargetFrameworkProfile />
|
<TargetFrameworkProfile />
|
||||||
<NuGetPackageImportStamp>
|
<NuGetPackageImportStamp>
|
||||||
</NuGetPackageImportStamp>
|
</NuGetPackageImportStamp>
|
||||||
|
<PublishUrl>publish\</PublishUrl>
|
||||||
|
<Install>true</Install>
|
||||||
|
<InstallFrom>Disk</InstallFrom>
|
||||||
|
<UpdateEnabled>false</UpdateEnabled>
|
||||||
|
<UpdateMode>Foreground</UpdateMode>
|
||||||
|
<UpdateInterval>7</UpdateInterval>
|
||||||
|
<UpdateIntervalUnits>Days</UpdateIntervalUnits>
|
||||||
|
<UpdatePeriodically>false</UpdatePeriodically>
|
||||||
|
<UpdateRequired>false</UpdateRequired>
|
||||||
|
<MapFileExtensions>true</MapFileExtensions>
|
||||||
|
<ApplicationRevision>0</ApplicationRevision>
|
||||||
|
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
|
||||||
|
<IsWebBootstrapper>false</IsWebBootstrapper>
|
||||||
|
<UseApplicationTrust>false</UseApplicationTrust>
|
||||||
|
<BootstrapperEnabled>true</BootstrapperEnabled>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
|
||||||
<DebugSymbols>true</DebugSymbols>
|
<DebugSymbols>true</DebugSymbols>
|
||||||
@@ -44,11 +59,17 @@
|
|||||||
<ApplicationIcon>torchicon.ico</ApplicationIcon>
|
<ApplicationIcon>torchicon.ico</ApplicationIcon>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<Reference Include="ControlzEx, Version=3.0.2.4, Culture=neutral, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\ControlzEx.3.0.2.4\lib\net45\ControlzEx.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
<Reference Include="HavokWrapper, Version=1.0.6051.28726, Culture=neutral, processorArchitecture=AMD64">
|
<Reference Include="HavokWrapper, Version=1.0.6051.28726, Culture=neutral, processorArchitecture=AMD64">
|
||||||
<SpecificVersion>False</SpecificVersion>
|
<SpecificVersion>False</SpecificVersion>
|
||||||
<HintPath>..\GameBinaries\HavokWrapper.dll</HintPath>
|
<HintPath>..\GameBinaries\HavokWrapper.dll</HintPath>
|
||||||
<Private>False</Private>
|
<Private>False</Private>
|
||||||
</Reference>
|
</Reference>
|
||||||
|
<Reference Include="MahApps.Metro, Version=1.6.1.4, Culture=neutral, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\MahApps.Metro.1.6.1\lib\net45\MahApps.Metro.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
<Reference Include="Microsoft.CodeAnalysis, Version=1.2.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
<Reference Include="Microsoft.CodeAnalysis, Version=1.2.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||||
<SpecificVersion>False</SpecificVersion>
|
<SpecificVersion>False</SpecificVersion>
|
||||||
<HintPath>..\GameBinaries\Microsoft.CodeAnalysis.dll</HintPath>
|
<HintPath>..\GameBinaries\Microsoft.CodeAnalysis.dll</HintPath>
|
||||||
@@ -96,18 +117,20 @@
|
|||||||
<HintPath>..\GameBinaries\SpaceEngineers.ObjectBuilders.XmlSerializers.dll</HintPath>
|
<HintPath>..\GameBinaries\SpaceEngineers.ObjectBuilders.XmlSerializers.dll</HintPath>
|
||||||
<Private>False</Private>
|
<Private>False</Private>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="SteamSDK, Version=0.0.0.0, Culture=neutral, processorArchitecture=AMD64">
|
<Reference Include="Steamworks.NET">
|
||||||
<SpecificVersion>False</SpecificVersion>
|
<HintPath>..\GameBinaries\Steamworks.NET.dll</HintPath>
|
||||||
<HintPath>..\GameBinaries\SteamSDK.dll</HintPath>
|
|
||||||
<Private>False</Private>
|
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="System" />
|
<Reference Include="System" />
|
||||||
|
<Reference Include="System.ComponentModel.DataAnnotations" />
|
||||||
<Reference Include="System.Configuration.Install" />
|
<Reference Include="System.Configuration.Install" />
|
||||||
<Reference Include="System.Data" />
|
<Reference Include="System.Data" />
|
||||||
<Reference Include="System.Drawing" />
|
<Reference Include="System.Drawing" />
|
||||||
<Reference Include="System.IO.Compression.FileSystem" />
|
<Reference Include="System.IO.Compression.FileSystem" />
|
||||||
<Reference Include="System.ServiceProcess" />
|
<Reference Include="System.ServiceProcess" />
|
||||||
<Reference Include="System.Windows.Forms" />
|
<Reference Include="System.Windows.Forms" />
|
||||||
|
<Reference Include="System.Windows.Interactivity, Version=4.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\packages\ControlzEx.3.0.2.4\lib\net45\System.Windows.Interactivity.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
<Reference Include="System.Xml" />
|
<Reference Include="System.Xml" />
|
||||||
<Reference Include="Microsoft.CSharp" />
|
<Reference Include="Microsoft.CSharp" />
|
||||||
<Reference Include="System.Core" />
|
<Reference Include="System.Core" />
|
||||||
@@ -194,15 +217,18 @@
|
|||||||
<Compile Include="..\Versioning\AssemblyVersion.cs">
|
<Compile Include="..\Versioning\AssemblyVersion.cs">
|
||||||
<Link>Properties\AssemblyVersion.cs</Link>
|
<Link>Properties\AssemblyVersion.cs</Link>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Include="Commands\WhitelistCommands.cs" />
|
||||||
|
<Compile Include="FlowDocumentTarget.cs" />
|
||||||
<Compile Include="ListBoxExtensions.cs" />
|
<Compile Include="ListBoxExtensions.cs" />
|
||||||
<Compile Include="Managers\EntityControlManager.cs" />
|
<Compile Include="Managers\EntityControlManager.cs" />
|
||||||
<Compile Include="Managers\MultiplayerManagerDedicated.cs" />
|
<Compile Include="Managers\MultiplayerManagerDedicated.cs" />
|
||||||
<Compile Include="Managers\InstanceManager.cs" />
|
<Compile Include="Managers\InstanceManager.cs" />
|
||||||
<Compile Include="Managers\MultiplayerManagerDedicatedEventShim.cs" />
|
<Compile Include="Managers\MultiplayerManagerDedicatedEventShim.cs" />
|
||||||
|
<Compile Include="Managers\MultiplayerManagerDedicatedPatchShim.cs" />
|
||||||
<Compile Include="NativeMethods.cs" />
|
<Compile Include="NativeMethods.cs" />
|
||||||
<Compile Include="Initializer.cs" />
|
<Compile Include="Initializer.cs" />
|
||||||
|
<Compile Include="Properties\Annotations.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
<Compile Include="ServerStatistics.cs" />
|
|
||||||
<Compile Include="TorchConfig.cs" />
|
<Compile Include="TorchConfig.cs" />
|
||||||
<Compile Include="TorchService.cs">
|
<Compile Include="TorchService.cs">
|
||||||
<SubType>Component</SubType>
|
<SubType>Component</SubType>
|
||||||
@@ -211,12 +237,26 @@
|
|||||||
<SubType>Component</SubType>
|
<SubType>Component</SubType>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="ViewModels\BlockLimitViewModel.cs" />
|
<Compile Include="ViewModels\BlockLimitViewModel.cs" />
|
||||||
|
<Compile Include="ViewModels\CheckpointViewModel.cs" />
|
||||||
<Compile Include="ViewModels\Entities\Blocks\BlockViewModel.cs" />
|
<Compile Include="ViewModels\Entities\Blocks\BlockViewModel.cs" />
|
||||||
<Compile Include="ViewModels\Entities\Blocks\BlockViewModelGenerator.cs" />
|
<Compile Include="ViewModels\Entities\Blocks\BlockViewModelGenerator.cs" />
|
||||||
<Compile Include="ViewModels\Entities\Blocks\PropertyViewModel.cs" />
|
<Compile Include="ViewModels\Entities\Blocks\PropertyViewModel.cs" />
|
||||||
<Compile Include="ViewModels\Entities\CharacterViewModel.cs" />
|
<Compile Include="ViewModels\Entities\CharacterViewModel.cs" />
|
||||||
<Compile Include="ViewModels\ConfigDedicatedViewModel.cs" />
|
<Compile Include="ViewModels\ConfigDedicatedViewModel.cs" />
|
||||||
<Compile Include="ViewModels\Entities\EntityControlViewModel.cs" />
|
<Compile Include="ViewModels\Entities\EntityControlViewModel.cs" />
|
||||||
|
<Compile Include="ViewModels\SessionSettingsViewModel.cs" />
|
||||||
|
<Compile Include="Views\Converters\DefinitionToIdConverter.cs" />
|
||||||
|
<Compile Include="Views\Converters\BooleanAndConverter.cs" />
|
||||||
|
<Compile Include="Views\Converters\ListConverter.cs" />
|
||||||
|
<Compile Include="MultiTextWriter.cs" />
|
||||||
|
<Compile Include="RichTextBoxWriter.cs" />
|
||||||
|
<Compile Include="Views\Entities\CharacterView.xaml.cs">
|
||||||
|
<DependentUpon>CharacterView.xaml</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="Views\ThemeControl.xaml.cs">
|
||||||
|
<DependentUpon>ThemeControl.xaml</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="Views\ValidationRules\ListConverterValidationRule.cs" />
|
||||||
<Compile Include="Views\Entities\EntityControlHost.xaml.cs">
|
<Compile Include="Views\Entities\EntityControlHost.xaml.cs">
|
||||||
<DependentUpon>EntityControlHost.xaml</DependentUpon>
|
<DependentUpon>EntityControlHost.xaml</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
@@ -230,7 +270,6 @@
|
|||||||
<Compile Include="ViewModels\ILazyLoad.cs" />
|
<Compile Include="ViewModels\ILazyLoad.cs" />
|
||||||
<Compile Include="ViewModels\PluginManagerViewModel.cs" />
|
<Compile Include="ViewModels\PluginManagerViewModel.cs" />
|
||||||
<Compile Include="ViewModels\PluginViewModel.cs" />
|
<Compile Include="ViewModels\PluginViewModel.cs" />
|
||||||
<Compile Include="ViewModels\SessionSettingsViewModel.cs" />
|
|
||||||
<Compile Include="ViewModels\Entities\VoxelMapViewModel.cs" />
|
<Compile Include="ViewModels\Entities\VoxelMapViewModel.cs" />
|
||||||
<Compile Include="ViewModels\SteamUserViewModel.cs" />
|
<Compile Include="ViewModels\SteamUserViewModel.cs" />
|
||||||
<Compile Include="Views\AddWorkshopItemsDialog.xaml.cs">
|
<Compile Include="Views\AddWorkshopItemsDialog.xaml.cs">
|
||||||
@@ -261,15 +300,15 @@
|
|||||||
<Compile Include="Views\Entities\VoxelMapView.xaml.cs">
|
<Compile Include="Views\Entities\VoxelMapView.xaml.cs">
|
||||||
<DependentUpon>VoxelMapView.xaml</DependentUpon>
|
<DependentUpon>VoxelMapView.xaml</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Views\FirstTimeSetup.xaml.cs">
|
|
||||||
<DependentUpon>FirstTimeSetup.xaml</DependentUpon>
|
|
||||||
</Compile>
|
|
||||||
<Compile Include="Views\ModsControl.xaml.cs">
|
<Compile Include="Views\ModsControl.xaml.cs">
|
||||||
<DependentUpon>ModsControl.xaml</DependentUpon>
|
<DependentUpon>ModsControl.xaml</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Views\PluginsControl.xaml.cs">
|
<Compile Include="Views\PluginsControl.xaml.cs">
|
||||||
<DependentUpon>PluginsControl.xaml</DependentUpon>
|
<DependentUpon>PluginsControl.xaml</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Include="Views\SessionSettingsView.xaml.cs">
|
||||||
|
<DependentUpon>SessionSettingsView.xaml</DependentUpon>
|
||||||
|
</Compile>
|
||||||
<Compile Include="Views\TorchUI.xaml.cs">
|
<Compile Include="Views\TorchUI.xaml.cs">
|
||||||
<DependentUpon>TorchUI.xaml</DependentUpon>
|
<DependentUpon>TorchUI.xaml</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
@@ -278,6 +317,10 @@
|
|||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Program.cs" />
|
<Compile Include="Program.cs" />
|
||||||
<Compile Include="TorchServer.cs" />
|
<Compile Include="TorchServer.cs" />
|
||||||
|
<Compile Include="Views\ValidationRules\NumberValidationRule.cs" />
|
||||||
|
<Compile Include="Views\WorldGeneratorDialog.xaml.cs">
|
||||||
|
<DependentUpon>WorldGeneratorDialog.xaml</DependentUpon>
|
||||||
|
</Compile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="Properties\Resources.Designer.cs">
|
<Compile Include="Properties\Resources.Designer.cs">
|
||||||
@@ -314,6 +357,22 @@
|
|||||||
</ProjectReference>
|
</ProjectReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<Page Include="Themes\Dark Theme Animated.xaml">
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
</Page>
|
||||||
|
<Page Include="Themes\Dark Theme.xaml">
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
</Page>
|
||||||
|
<Page Include="Themes\Light Theme Animated.xaml">
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
</Page>
|
||||||
|
<Page Include="Themes\Light Theme.xaml">
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
</Page>
|
||||||
<Page Include="Views\Entities\EntityControlHost.xaml">
|
<Page Include="Views\Entities\EntityControlHost.xaml">
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
@@ -346,6 +405,10 @@
|
|||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
</Page>
|
</Page>
|
||||||
|
<Page Include="Views\Entities\CharacterView.xaml">
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
</Page>
|
||||||
<Page Include="Views\Entities\GridView.xaml">
|
<Page Include="Views\Entities\GridView.xaml">
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
@@ -358,14 +421,22 @@
|
|||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
</Page>
|
</Page>
|
||||||
<Page Include="Views\FirstTimeSetup.xaml">
|
|
||||||
<SubType>Designer</SubType>
|
|
||||||
<Generator>MSBuild:Compile</Generator>
|
|
||||||
</Page>
|
|
||||||
<Page Include="Views\ModsControl.xaml">
|
<Page Include="Views\ModsControl.xaml">
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
</Page>
|
</Page>
|
||||||
|
<Page Include="Views\Resources.xaml">
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
</Page>
|
||||||
|
<Page Include="Views\SessionSettingsView.xaml">
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
</Page>
|
||||||
|
<Page Include="Views\ThemeControl.xaml">
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
</Page>
|
||||||
<Page Include="Views\TorchUI.xaml">
|
<Page Include="Views\TorchUI.xaml">
|
||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
@@ -374,6 +445,10 @@
|
|||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
</Page>
|
</Page>
|
||||||
|
<Page Include="Views\WorldGeneratorDialog.xaml">
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
</Page>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Resource Include="torchicon.ico" />
|
<Resource Include="torchicon.ico" />
|
||||||
@@ -381,7 +456,18 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Service Include="{508349B6-6B84-4DF5-91F0-309BEEBAD82D}" />
|
<Service Include="{508349B6-6B84-4DF5-91F0-309BEEBAD82D}" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup />
|
<ItemGroup>
|
||||||
|
<BootstrapperPackage Include=".NETFramework,Version=v4.6.1">
|
||||||
|
<Visible>False</Visible>
|
||||||
|
<ProductName>Microsoft .NET Framework 4.6.1 %28x86 and x64%29</ProductName>
|
||||||
|
<Install>true</Install>
|
||||||
|
</BootstrapperPackage>
|
||||||
|
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
|
||||||
|
<Visible>False</Visible>
|
||||||
|
<ProductName>.NET Framework 3.5 SP1</ProductName>
|
||||||
|
<Install>false</Install>
|
||||||
|
</BootstrapperPackage>
|
||||||
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
<Import Project="$(SolutionDir)\TransformOnBuild.targets" />
|
<Import Project="$(SolutionDir)\TransformOnBuild.targets" />
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
|
@@ -60,8 +60,22 @@ namespace Torch.Server
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public List<string> Plugins { get; set; } = new List<string>();
|
public List<string> Plugins { get; set; } = new List<string>();
|
||||||
|
|
||||||
|
public bool EnableWhitelist { get; set; } = false;
|
||||||
|
public HashSet<ulong> Whitelist { get; set; } = new HashSet<ulong>();
|
||||||
|
|
||||||
internal Point WindowSize { get; set; } = new Point(800, 600);
|
internal Point WindowSize { get; set; } = new Point(800, 600);
|
||||||
internal Point WindowPosition { get; set; } = new Point();
|
internal Point WindowPosition { get; set; } = new Point();
|
||||||
|
|
||||||
|
public string LastUsedTheme { get; set; } = "Torch Theme";
|
||||||
|
|
||||||
|
//TODO: REMOVE ME BY JULY 2019
|
||||||
|
[Obsolete("Use vanilla reserved slot config")]
|
||||||
|
public HashSet<ulong> ReservedPlayers { get; set; } = new HashSet<ulong>();
|
||||||
|
|
||||||
|
//Prevent reserved players being written to disk, but allow it to bre read
|
||||||
|
//remove this when ReservedPlayers is removed
|
||||||
|
private bool ShouldSerializeReservedPlayers() => false;
|
||||||
|
|
||||||
[XmlIgnore]
|
[XmlIgnore]
|
||||||
private string _path;
|
private string _path;
|
||||||
|
|
||||||
|
@@ -1,40 +1,35 @@
|
|||||||
using Sandbox;
|
#region
|
||||||
using Sandbox.Engine.Utils;
|
|
||||||
using Sandbox.Game;
|
|
||||||
using Sandbox.Game.World;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Globalization;
|
using System.Net;
|
||||||
using System.IO;
|
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Security.Principal;
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.Xml.Serialization.GeneratedAssembly;
|
using System.Windows.Forms;
|
||||||
using NLog;
|
using NLog;
|
||||||
using Sandbox.Engine.Analytics;
|
using Sandbox;
|
||||||
|
using Sandbox.Engine.Networking;
|
||||||
using Sandbox.Game.Multiplayer;
|
using Sandbox.Game.Multiplayer;
|
||||||
using Sandbox.ModAPI;
|
using Sandbox.Game.World;
|
||||||
using SteamSDK;
|
|
||||||
using Torch.API;
|
using Torch.API;
|
||||||
using Torch.API.Managers;
|
using Torch.API.Managers;
|
||||||
using Torch.API.Session;
|
using Torch.API.Session;
|
||||||
using Torch.Managers;
|
using Torch.Commands;
|
||||||
|
using Torch.Mod;
|
||||||
|
using Torch.Server.Commands;
|
||||||
using Torch.Server.Managers;
|
using Torch.Server.Managers;
|
||||||
using Torch.Utils;
|
using Torch.Utils;
|
||||||
|
using VRage;
|
||||||
using VRage.Dedicated;
|
using VRage.Dedicated;
|
||||||
using VRage.FileSystem;
|
using VRage.Dedicated.RemoteAPI;
|
||||||
using VRage.Game;
|
using VRage.GameServices;
|
||||||
using VRage.Game.ModAPI;
|
using VRage.Steam;
|
||||||
using VRage.Game.ObjectBuilder;
|
using Timer = System.Threading.Timer;
|
||||||
using VRage.Game.SessionComponents;
|
|
||||||
using VRage.Library;
|
#endregion
|
||||||
using VRage.ObjectBuilders;
|
|
||||||
using VRage.Plugins;
|
|
||||||
using VRage.Utils;
|
|
||||||
|
|
||||||
#pragma warning disable 618
|
#pragma warning disable 618
|
||||||
|
|
||||||
@@ -42,53 +37,40 @@ namespace Torch.Server
|
|||||||
{
|
{
|
||||||
public class TorchServer : TorchBase, ITorchServer
|
public class TorchServer : TorchBase, ITorchServer
|
||||||
{
|
{
|
||||||
//public MyConfigDedicated<MyObjectBuilder_SessionSettings> DedicatedConfig { get; set; }
|
private bool _canRun;
|
||||||
|
private TimeSpan _elapsedPlayTime;
|
||||||
|
private bool _hasRun;
|
||||||
|
private bool _isRunning;
|
||||||
|
private float _simRatio;
|
||||||
|
private ServerState _state;
|
||||||
|
private Stopwatch _uptime;
|
||||||
|
private Timer _watchdog;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public float SimulationRatio
|
public TorchServer(TorchConfig config = null)
|
||||||
{
|
{
|
||||||
get => _simRatio;
|
DedicatedInstance = new InstanceManager(this);
|
||||||
set
|
AddManager(DedicatedInstance);
|
||||||
{
|
AddManager(new EntityControlManager(this));
|
||||||
_simRatio = value;
|
Config = config ?? new TorchConfig();
|
||||||
OnPropertyChanged();
|
|
||||||
}
|
var sessionManager = Managers.GetManager<ITorchSessionManager>();
|
||||||
|
sessionManager.AddFactory(x => new MultiplayerManagerDedicated(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public TimeSpan ElapsedPlayTime
|
public float SimulationRatio { get => _simRatio; set => SetValue(ref _simRatio, value); }
|
||||||
{
|
|
||||||
get => _elapsedPlayTime;
|
/// <inheritdoc />
|
||||||
set
|
public TimeSpan ElapsedPlayTime { get => _elapsedPlayTime; set => SetValue(ref _elapsedPlayTime, value); }
|
||||||
{
|
|
||||||
_elapsedPlayTime = value;
|
|
||||||
OnPropertyChanged();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public Thread GameThread { get; private set; }
|
public Thread GameThread { get; private set; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public ServerState State
|
public bool IsRunning { get => _isRunning; set => SetValue(ref _isRunning, value); }
|
||||||
{
|
|
||||||
get => _state;
|
|
||||||
private set
|
|
||||||
{
|
|
||||||
_state = value;
|
|
||||||
OnPropertyChanged();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
public bool CanRun { get => _canRun; set => SetValue(ref _canRun, value); }
|
||||||
public bool IsRunning
|
|
||||||
{
|
|
||||||
get => _isRunning;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
_isRunning = value;
|
|
||||||
OnPropertyChanged();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public InstanceManager DedicatedInstance { get; }
|
public InstanceManager DedicatedInstance { get; }
|
||||||
@@ -97,52 +79,30 @@ namespace Torch.Server
|
|||||||
public string InstanceName => Config?.InstanceName;
|
public string InstanceName => Config?.InstanceName;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public string InstancePath => Config?.InstancePath;
|
|
||||||
|
|
||||||
private bool _isRunning;
|
|
||||||
private ServerState _state;
|
|
||||||
private TimeSpan _elapsedPlayTime;
|
|
||||||
private float _simRatio;
|
|
||||||
private Timer _watchdog;
|
|
||||||
private Stopwatch _uptime;
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public TorchServer(TorchConfig config = null)
|
|
||||||
{
|
|
||||||
DedicatedInstance = new InstanceManager(this);
|
|
||||||
AddManager(DedicatedInstance);
|
|
||||||
AddManager(new EntityControlManager(this));
|
|
||||||
Config = config ?? new TorchConfig();
|
|
||||||
|
|
||||||
var sessionManager = Managers.GetManager<ITorchSessionManager>();
|
|
||||||
sessionManager.AddFactory((x) => new MultiplayerManagerDedicated(this));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
protected override uint SteamAppId => 244850;
|
protected override uint SteamAppId => 244850;
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc />
|
||||||
protected override string SteamAppName => "SpaceEngineersDedicated";
|
protected override string SteamAppName => "SpaceEngineersDedicated";
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public ServerState State { get => _state; private set => SetValue(ref _state, value); }
|
||||||
|
|
||||||
|
public event Action<ITorchServer> Initialized;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public string InstancePath => Config?.InstancePath;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void Init()
|
public override void Init()
|
||||||
{
|
{
|
||||||
Log.Info($"Init server '{Config.InstanceName}' at '{Config.InstancePath}'");
|
Log.Info("Initializing server");
|
||||||
Sandbox.Engine.Platform.Game.IsDedicated = true;
|
MySandboxGame.IsDedicated = true;
|
||||||
|
|
||||||
base.Init();
|
base.Init();
|
||||||
|
|
||||||
Managers.GetManager<ITorchSessionManager>().SessionStateChanged += OnSessionStateChanged;
|
Managers.GetManager<ITorchSessionManager>().SessionStateChanged += OnSessionStateChanged;
|
||||||
GetManager<InstanceManager>().LoadInstance(Config.InstancePath);
|
GetManager<InstanceManager>().LoadInstance(Config.InstancePath);
|
||||||
}
|
CanRun = true;
|
||||||
|
Initialized?.Invoke(this);
|
||||||
private void OnSessionStateChanged(ITorchSession session, TorchSessionState newState)
|
Log.Info($"Initialized server '{Config.InstanceName}' at '{Config.InstancePath}'");
|
||||||
{
|
|
||||||
if (newState == TorchSessionState.Unloading || newState == TorchSessionState.Unloaded)
|
|
||||||
{
|
|
||||||
_watchdog?.Dispose();
|
|
||||||
_watchdog = null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@@ -150,12 +110,25 @@ namespace Torch.Server
|
|||||||
{
|
{
|
||||||
if (State != ServerState.Stopped)
|
if (State != ServerState.Stopped)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (_hasRun)
|
||||||
|
{
|
||||||
|
Restart();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
State = ServerState.Starting;
|
State = ServerState.Starting;
|
||||||
IsRunning = true;
|
IsRunning = true;
|
||||||
|
CanRun = false;
|
||||||
|
_hasRun = true;
|
||||||
Log.Info("Starting server.");
|
Log.Info("Starting server.");
|
||||||
MySandboxGame.ConfigDedicated = DedicatedInstance.DedicatedConfig.Model;
|
MySandboxGame.ConfigDedicated = DedicatedInstance.DedicatedConfig.Model;
|
||||||
|
if (MySandboxGame.ConfigDedicated.RemoteApiEnabled && !string.IsNullOrEmpty(MySandboxGame.ConfigDedicated.RemoteSecurityKey))
|
||||||
|
{
|
||||||
|
var myRemoteServer = new MyRemoteServer(MySandboxGame.ConfigDedicated.RemoteApiPort, MySandboxGame.ConfigDedicated.RemoteSecurityKey);
|
||||||
|
Log.Info($"Remote API started on port {myRemoteServer.Port}");
|
||||||
|
}
|
||||||
|
|
||||||
DedicatedInstance.SaveConfig();
|
|
||||||
_uptime = Stopwatch.StartNew();
|
_uptime = Stopwatch.StartNew();
|
||||||
base.Start();
|
base.Start();
|
||||||
}
|
}
|
||||||
@@ -171,23 +144,51 @@ namespace Torch.Server
|
|||||||
|
|
||||||
State = ServerState.Stopped;
|
State = ServerState.Stopped;
|
||||||
IsRunning = false;
|
IsRunning = false;
|
||||||
|
CanRun = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Restart the program.
|
/// Restart the program.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public override void Restart()
|
public override void Restart()
|
||||||
{
|
{
|
||||||
Save(0).Wait();
|
if (IsRunning)
|
||||||
Stop();
|
Save().ContinueWith(DoRestart, this, TaskContinuationOptions.RunContinuationsAsynchronously);
|
||||||
LogManager.Flush();
|
else
|
||||||
|
DoRestart(null, this);
|
||||||
|
|
||||||
var exe = Assembly.GetExecutingAssembly().Location;
|
void DoRestart(Task<GameSaveResult> task, object torch0)
|
||||||
((TorchConfig)Config).WaitForPID = Process.GetCurrentProcess().Id.ToString();
|
{
|
||||||
Config.Autostart = true;
|
var torch = (TorchServer)torch0;
|
||||||
Process.Start(exe, Config.ToString());
|
torch.Stop();
|
||||||
|
// TODO clone this
|
||||||
|
var config = (TorchConfig)torch.Config;
|
||||||
|
LogManager.Flush();
|
||||||
|
|
||||||
Process.GetCurrentProcess().Kill();
|
string exe = Assembly.GetExecutingAssembly().Location;
|
||||||
|
Debug.Assert(exe != null);
|
||||||
|
config.WaitForPID = Process.GetCurrentProcess().Id.ToString();
|
||||||
|
config.Autostart = true;
|
||||||
|
Process.Start(exe, config.ToString());
|
||||||
|
|
||||||
|
Process.GetCurrentProcess().Kill();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnSessionStateChanged(ITorchSession session, TorchSessionState newState)
|
||||||
|
{
|
||||||
|
if (newState == TorchSessionState.Unloading || newState == TorchSessionState.Unloaded)
|
||||||
|
{
|
||||||
|
_watchdog?.Dispose();
|
||||||
|
_watchdog = null;
|
||||||
|
ModCommunication.Unregister();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newState == TorchSessionState.Loaded)
|
||||||
|
{
|
||||||
|
CurrentSession.Managers.GetManager<CommandManager>().RegisterCommandModule(typeof(WhitelistCommands));
|
||||||
|
ModCommunication.Register();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@@ -196,21 +197,17 @@ namespace Torch.Server
|
|||||||
base.Init(gameInstance);
|
base.Init(gameInstance);
|
||||||
var game = gameInstance as MySandboxGame;
|
var game = gameInstance as MySandboxGame;
|
||||||
if (game != null && MySession.Static != null)
|
if (game != null && MySession.Static != null)
|
||||||
{
|
|
||||||
State = ServerState.Running;
|
State = ServerState.Running;
|
||||||
// SteamServerAPI.Instance.GameServer.SetKeyValue("SM", "Torch");
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
|
||||||
State = ServerState.Stopped;
|
State = ServerState.Stopped;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void Update()
|
public override void Update()
|
||||||
{
|
{
|
||||||
base.Update();
|
base.Update();
|
||||||
SimulationRatio = Sync.ServerSimulationRatio;
|
// Stops 1.00-1.02 flicker.
|
||||||
|
SimulationRatio = Math.Min(Sync.ServerSimulationRatio, 1);
|
||||||
var elapsed = TimeSpan.FromSeconds(Math.Floor(_uptime.Elapsed.TotalSeconds));
|
var elapsed = TimeSpan.FromSeconds(Math.Floor(_uptime.Elapsed.TotalSeconds));
|
||||||
ElapsedPlayTime = elapsed;
|
ElapsedPlayTime = elapsed;
|
||||||
|
|
||||||
@@ -227,7 +224,7 @@ namespace Torch.Server
|
|||||||
private static void CheckServerResponding(object state)
|
private static void CheckServerResponding(object state)
|
||||||
{
|
{
|
||||||
var mre = new ManualResetEvent(false);
|
var mre = new ManualResetEvent(false);
|
||||||
((TorchServer) state).Invoke(() => mre.Set());
|
((TorchServer)state).Invoke(() => mre.Set());
|
||||||
if (!mre.WaitOne(TimeSpan.FromSeconds(Instance.Config.TickTimeout)))
|
if (!mre.WaitOne(TimeSpan.FromSeconds(Instance.Config.TickTimeout)))
|
||||||
{
|
{
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
@@ -239,10 +236,8 @@ namespace Torch.Server
|
|||||||
throw new TimeoutException($"Server watchdog detected that the server was frozen for at least {((TorchServer)state).Config.TickTimeout} seconds.");
|
throw new TimeoutException($"Server watchdog detected that the server was frozen for at least {((TorchServer)state).Config.TickTimeout} seconds.");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
Log.Debug("Server watchdog responded");
|
||||||
Log.Debug("Server watchdog responded");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string DumpFrozenThread(Thread thread, int traces = 3, int pause = 5000)
|
private static string DumpFrozenThread(Thread thread, int traces = 3, int pause = 5000)
|
||||||
@@ -256,6 +251,7 @@ namespace Torch.Server
|
|||||||
stacks.Add(dump);
|
stacks.Add(dump);
|
||||||
Thread.Sleep(pause);
|
Thread.Sleep(pause);
|
||||||
}
|
}
|
||||||
|
|
||||||
string commonPrefix = StringUtils.CommonSuffix(stacks);
|
string commonPrefix = StringUtils.CommonSuffix(stacks);
|
||||||
// Advance prefix to include the line terminator.
|
// Advance prefix to include the line terminator.
|
||||||
commonPrefix = commonPrefix.Substring(commonPrefix.IndexOf('\n') + 1);
|
commonPrefix = commonPrefix.Substring(commonPrefix.IndexOf('\n') + 1);
|
||||||
@@ -269,6 +265,7 @@ namespace Torch.Server
|
|||||||
result.AppendLine($"Suffix {i}");
|
result.AppendLine($"Suffix {i}");
|
||||||
result.AppendLine(stacks[i].Substring(0, stacks[i].Length - commonPrefix.Length));
|
result.AppendLine(stacks[i].Substring(0, stacks[i].Length - commonPrefix.Length));
|
||||||
}
|
}
|
||||||
|
|
||||||
return result.ToString();
|
return result.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -282,6 +279,7 @@ namespace Torch.Server
|
|||||||
{
|
{
|
||||||
// ignored
|
// ignored
|
||||||
}
|
}
|
||||||
|
|
||||||
var stack = new StackTrace(thread, true);
|
var stack = new StackTrace(thread, true);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -291,51 +289,10 @@ namespace Torch.Server
|
|||||||
{
|
{
|
||||||
// ignored
|
// ignored
|
||||||
}
|
}
|
||||||
|
|
||||||
return stack;
|
return stack;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public override Task Save(long callerId)
|
|
||||||
{
|
|
||||||
return SaveGameAsync(statusCode => SaveCompleted(statusCode, callerId));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Callback for when save has finished.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="statusCode">Return code of the save operation</param>
|
|
||||||
/// <param name="callerId">Caller of the save operation</param>
|
|
||||||
private void SaveCompleted(SaveGameStatus statusCode, long callerId = 0)
|
|
||||||
{
|
|
||||||
string response = null;
|
|
||||||
switch (statusCode)
|
|
||||||
{
|
|
||||||
case SaveGameStatus.Success:
|
|
||||||
Log.Info("Save completed.");
|
|
||||||
response = "Saved game.";
|
|
||||||
break;
|
|
||||||
case SaveGameStatus.SaveInProgress:
|
|
||||||
Log.Error("Save failed, a save is already in progress.");
|
|
||||||
response = "Save failed, a save is already in progress.";
|
|
||||||
break;
|
|
||||||
case SaveGameStatus.GameNotReady:
|
|
||||||
Log.Error("Save failed, game was not ready.");
|
|
||||||
response = "Save failed, game was not ready.";
|
|
||||||
break;
|
|
||||||
case SaveGameStatus.TimedOut:
|
|
||||||
Log.Error("Save failed, save timed out.");
|
|
||||||
response = "Save failed, save timed out.";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (MySession.Static.Players.TryGetPlayerId(callerId, out MyPlayer.PlayerId result))
|
|
||||||
{
|
|
||||||
Managers.GetManager<IChatManagerServer>()?.SendMessageAsOther("Server", response,
|
|
||||||
statusCode == SaveGameStatus.Success ? MyFontEnum.Green : MyFontEnum.Red, result.SteamId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
132
Torch.Server/ViewModels/CheckpointViewModel.cs
Normal file
132
Torch.Server/ViewModels/CheckpointViewModel.cs
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Torch.Collections;
|
||||||
|
using VRage;
|
||||||
|
using VRage.Game;
|
||||||
|
using VRage.Game.ModAPI;
|
||||||
|
using VRage.ObjectBuilders;
|
||||||
|
using VRage.Serialization;
|
||||||
|
using VRageMath;
|
||||||
|
|
||||||
|
namespace Torch.Server.ViewModels
|
||||||
|
{
|
||||||
|
public class CheckpointViewModel : ViewModel
|
||||||
|
{
|
||||||
|
private MyObjectBuilder_Checkpoint _checkpoint;
|
||||||
|
private SessionSettingsViewModel _sessionSettings;
|
||||||
|
|
||||||
|
public CheckpointViewModel(MyObjectBuilder_Checkpoint checkpoint)
|
||||||
|
{
|
||||||
|
_checkpoint = checkpoint;
|
||||||
|
_sessionSettings = new SessionSettingsViewModel(_checkpoint.Settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static implicit operator MyObjectBuilder_Checkpoint(CheckpointViewModel model)
|
||||||
|
{
|
||||||
|
return model._checkpoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector3I CurrentSector { get => _checkpoint.CurrentSector; set => SetValue(ref _checkpoint.CurrentSector, value); }
|
||||||
|
|
||||||
|
public long ElapsedGameTime { get => _checkpoint.ElapsedGameTime; set => SetValue(ref _checkpoint.ElapsedGameTime, value); }
|
||||||
|
|
||||||
|
public string SessionName { get => _checkpoint.SessionName; set => SetValue(ref _checkpoint.SessionName, value); }
|
||||||
|
|
||||||
|
public MyPositionAndOrientation SpectatorPosition { get => _checkpoint.SpectatorPosition; set => SetValue(ref _checkpoint.SpectatorPosition, value); }
|
||||||
|
|
||||||
|
public bool SpectatorIsLightOn { get => _checkpoint.SpectatorIsLightOn; set => SetValue(ref _checkpoint.SpectatorIsLightOn, value); }
|
||||||
|
|
||||||
|
public MyCameraControllerEnum CameraController { get => _checkpoint.CameraController; set => SetValue(ref _checkpoint.CameraController, value); }
|
||||||
|
|
||||||
|
public long CameraEntity { get => _checkpoint.CameraEntity; set => SetValue(ref _checkpoint.CameraEntity, value); }
|
||||||
|
|
||||||
|
public long ControlledObject { get => _checkpoint.ControlledObject; set => SetValue(ref _checkpoint.ControlledObject, value); }
|
||||||
|
|
||||||
|
public string Password { get => _checkpoint.Password; set => SetValue(ref _checkpoint.Password, value); }
|
||||||
|
|
||||||
|
public string Description { get => _checkpoint.Description; set => SetValue(ref _checkpoint.Description, value); }
|
||||||
|
|
||||||
|
public DateTime LastSaveTime { get => _checkpoint.LastSaveTime; set => SetValue(ref _checkpoint.LastSaveTime, value); }
|
||||||
|
|
||||||
|
public float SpectatorDistance { get => _checkpoint.SpectatorDistance; set => SetValue(ref _checkpoint.SpectatorDistance, value); }
|
||||||
|
|
||||||
|
public ulong? WorkshopId { get => _checkpoint.WorkshopId; set => SetValue(ref _checkpoint.WorkshopId, value); }
|
||||||
|
|
||||||
|
public MyObjectBuilder_Toolbar CharacterToolbar { get => _checkpoint.CharacterToolbar; set => SetValue(ref _checkpoint.CharacterToolbar, value); }
|
||||||
|
|
||||||
|
public SerializableDictionary<long, MyObjectBuilder_Checkpoint.PlayerId> ControlledEntities { get => _checkpoint.ControlledEntities; set => SetValue(ref _checkpoint.ControlledEntities, value); }
|
||||||
|
|
||||||
|
public SessionSettingsViewModel Settings
|
||||||
|
{
|
||||||
|
get => _sessionSettings;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
SetValue(ref _sessionSettings, value);
|
||||||
|
_checkpoint.Settings = _sessionSettings;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public MyObjectBuilder_ScriptManager ScriptManagerData => throw new NotImplementedException();
|
||||||
|
|
||||||
|
public int AppVersion { get => _checkpoint.AppVersion; set => SetValue(ref _checkpoint.AppVersion, value); }
|
||||||
|
|
||||||
|
public MyObjectBuilder_FactionCollection Factions => throw new NotImplementedException();
|
||||||
|
|
||||||
|
public List<MyObjectBuilder_Checkpoint.ModItem> Mods { get => _checkpoint.Mods; set => SetValue(ref _checkpoint.Mods, value); }
|
||||||
|
|
||||||
|
public SerializableDictionary<ulong, MyPromoteLevel> PromotedUsers { get => _checkpoint.PromotedUsers; set => SetValue(ref _checkpoint.PromotedUsers, value); }
|
||||||
|
|
||||||
|
public HashSet<ulong> CreativeTools { get => _checkpoint.CreativeTools; set => SetValue(ref _checkpoint.CreativeTools, value); }
|
||||||
|
|
||||||
|
public SerializableDefinitionId Scenario { get => _checkpoint.Scenario; set => SetValue(ref _checkpoint.Scenario, value); }
|
||||||
|
|
||||||
|
public List<MyObjectBuilder_Checkpoint.RespawnCooldownItem> RespawnCooldowns { get => _checkpoint.RespawnCooldowns; set => SetValue(ref _checkpoint.RespawnCooldowns, value); }
|
||||||
|
|
||||||
|
public List<MyObjectBuilder_Identity> Identities { get => _checkpoint.Identities; set => SetValue(ref _checkpoint.Identities, value); }
|
||||||
|
|
||||||
|
public List<MyObjectBuilder_Client> Clients { get => _checkpoint.Clients; set => SetValue(ref _checkpoint.Clients, value); }
|
||||||
|
|
||||||
|
public MyEnvironmentHostilityEnum? PreviousEnvironmentHostility { get => _checkpoint.PreviousEnvironmentHostility; set => SetValue(ref _checkpoint.PreviousEnvironmentHostility, value); }
|
||||||
|
|
||||||
|
public SerializableDictionary<MyObjectBuilder_Checkpoint.PlayerId, MyObjectBuilder_Player> AllPlayersData { get => _checkpoint.AllPlayersData; set => SetValue(ref _checkpoint.AllPlayersData, value); }
|
||||||
|
|
||||||
|
public SerializableDictionary<MyObjectBuilder_Checkpoint.PlayerId, List<Vector3>> AllPlayersColors { get => _checkpoint.AllPlayersColors; set => SetValue(ref _checkpoint.AllPlayersColors, value); }
|
||||||
|
|
||||||
|
public List<MyObjectBuilder_ChatHistory> ChatHistory { get => _checkpoint.ChatHistory; set => SetValue(ref _checkpoint.ChatHistory, value); }
|
||||||
|
|
||||||
|
public List<MyObjectBuilder_FactionChatHistory> FactionChatHistory { get => _checkpoint.FactionChatHistory; set => SetValue(ref _checkpoint.FactionChatHistory, value); }
|
||||||
|
|
||||||
|
public List<long> NonPlayerIdentities { get => _checkpoint.NonPlayerIdentities; set => SetValue(ref _checkpoint.NonPlayerIdentities, value); }
|
||||||
|
|
||||||
|
public SerializableDictionary<long, MyObjectBuilder_Gps> Gps { get => _checkpoint.Gps; set => SetValue(ref _checkpoint.Gps, value); }
|
||||||
|
|
||||||
|
public SerializableBoundingBoxD? WorldBoundaries { get => _checkpoint.WorldBoundaries; set => SetValue(ref _checkpoint.WorldBoundaries, value); }
|
||||||
|
|
||||||
|
public List<MyObjectBuilder_SessionComponent> SessionComponents { get => _checkpoint.SessionComponents; set => SetValue(ref _checkpoint.SessionComponents, value); }
|
||||||
|
|
||||||
|
public SerializableDefinitionId GameDefinition { get => _checkpoint.GameDefinition; set => SetValue(ref _checkpoint.GameDefinition, value); }
|
||||||
|
|
||||||
|
public HashSet<string> SessionComponentEnabled { get => _checkpoint.SessionComponentEnabled; set => SetValue(ref _checkpoint.SessionComponentEnabled, value); }
|
||||||
|
|
||||||
|
public HashSet<string> SessionComponentDisabled { get => _checkpoint.SessionComponentDisabled; set => SetValue(ref _checkpoint.SessionComponentDisabled, value); }
|
||||||
|
|
||||||
|
public DateTime InGameTime { get => _checkpoint.InGameTime; set => SetValue(ref _checkpoint.InGameTime, value); }
|
||||||
|
|
||||||
|
public MyObjectBuilder_SessionComponentMission MissionTriggers { get => _checkpoint.MissionTriggers; set => SetValue(ref _checkpoint.MissionTriggers, value); }
|
||||||
|
|
||||||
|
public string Briefing { get => _checkpoint.Briefing; set => SetValue(ref _checkpoint.Briefing, value); }
|
||||||
|
|
||||||
|
public string BriefingVideo { get => _checkpoint.BriefingVideo; set => SetValue(ref _checkpoint.BriefingVideo, value); }
|
||||||
|
|
||||||
|
public string CustomLoadingScreenImage { get => _checkpoint.CustomLoadingScreenImage; set => SetValue(ref _checkpoint.BriefingVideo, value); }
|
||||||
|
|
||||||
|
public string CustomLoadingScreenText { get => _checkpoint.CustomLoadingScreenText; set => SetValue(ref _checkpoint.CustomLoadingScreenText, value); }
|
||||||
|
|
||||||
|
public string CustomSkybox { get => _checkpoint.CustomSkybox; set => SetValue(ref _checkpoint.CustomSkybox, value); }
|
||||||
|
|
||||||
|
public int RequiresDX { get => _checkpoint.RequiresDX; set => SetValue(ref _checkpoint.RequiresDX, value); }
|
||||||
|
}
|
||||||
|
}
|
@@ -7,6 +7,7 @@ using System.Threading.Tasks;
|
|||||||
using NLog;
|
using NLog;
|
||||||
using Sandbox.Engine.Utils;
|
using Sandbox.Engine.Utils;
|
||||||
using Torch.Collections;
|
using Torch.Collections;
|
||||||
|
using Torch.Server.Managers;
|
||||||
using VRage.Game;
|
using VRage.Game;
|
||||||
using VRage.Game.ModAPI;
|
using VRage.Game.ModAPI;
|
||||||
|
|
||||||
@@ -14,7 +15,7 @@ namespace Torch.Server.ViewModels
|
|||||||
{
|
{
|
||||||
public class ConfigDedicatedViewModel : ViewModel
|
public class ConfigDedicatedViewModel : ViewModel
|
||||||
{
|
{
|
||||||
private static readonly Logger Log = LogManager.GetLogger("Config");
|
private static readonly Logger Log = LogManager.GetCurrentClassLogger();
|
||||||
private MyConfigDedicated<MyObjectBuilder_SessionSettings> _config;
|
private MyConfigDedicated<MyObjectBuilder_SessionSettings> _config;
|
||||||
public MyConfigDedicated<MyObjectBuilder_SessionSettings> Model => _config;
|
public MyConfigDedicated<MyObjectBuilder_SessionSettings> Model => _config;
|
||||||
|
|
||||||
@@ -28,106 +29,108 @@ namespace Torch.Server.ViewModels
|
|||||||
_config = configDedicated;
|
_config = configDedicated;
|
||||||
_config.IgnoreLastSession = true;
|
_config.IgnoreLastSession = true;
|
||||||
SessionSettings = new SessionSettingsViewModel(_config.SessionSettings);
|
SessionSettings = new SessionSettingsViewModel(_config.SessionSettings);
|
||||||
Administrators = string.Join(Environment.NewLine, _config.Administrators);
|
|
||||||
Banned = string.Join(Environment.NewLine, _config.Banned);
|
|
||||||
Mods = string.Join(Environment.NewLine, _config.Mods);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Save(string path = null)
|
public void Save(string path = null)
|
||||||
{
|
{
|
||||||
var newline = new [] {Environment.NewLine};
|
Validate();
|
||||||
|
|
||||||
_config.Administrators.Clear();
|
|
||||||
foreach (var admin in Administrators.Split(newline, StringSplitOptions.RemoveEmptyEntries))
|
|
||||||
_config.Administrators.Add(admin);
|
|
||||||
|
|
||||||
_config.Banned.Clear();
|
|
||||||
foreach (var banned in Banned.Split(newline, StringSplitOptions.RemoveEmptyEntries))
|
|
||||||
_config.Banned.Add(ulong.Parse(banned));
|
|
||||||
|
|
||||||
_config.Mods.Clear();
|
|
||||||
foreach (var mod in Mods.Split(newline, StringSplitOptions.RemoveEmptyEntries))
|
|
||||||
{
|
|
||||||
if (ulong.TryParse(mod, out ulong modId))
|
|
||||||
_config.Mods.Add(modId);
|
|
||||||
else
|
|
||||||
Log.Warn($"'{mod}' is not a valid mod ID.");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
_config.SessionSettings = _sessionSettings;
|
||||||
// Never ever
|
// Never ever
|
||||||
_config.IgnoreLastSession = true;
|
_config.IgnoreLastSession = true;
|
||||||
_config.Save(path);
|
_config.Save(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool Validate()
|
||||||
|
{
|
||||||
|
if (SelectedWorld == null)
|
||||||
|
{
|
||||||
|
Log.Warn($"{nameof(SelectedWorld)} == null");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (LoadWorld == null)
|
||||||
|
{
|
||||||
|
Log.Warn($"{nameof(LoadWorld)} == null");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
private SessionSettingsViewModel _sessionSettings;
|
private SessionSettingsViewModel _sessionSettings;
|
||||||
public SessionSettingsViewModel SessionSettings { get => _sessionSettings; set { _sessionSettings = value; OnPropertyChanged(); } }
|
public SessionSettingsViewModel SessionSettings { get => _sessionSettings; set { _sessionSettings = value; OnPropertyChanged(); } }
|
||||||
|
|
||||||
public MtObservableList<string> WorldPaths { get; } = new MtObservableList<string>();
|
public MtObservableList<WorldViewModel> Worlds { get; } = new MtObservableList<WorldViewModel>();
|
||||||
private string _administrators;
|
private WorldViewModel _selectedWorld;
|
||||||
public string Administrators { get => _administrators; set { _administrators = value; OnPropertyChanged(); } }
|
public WorldViewModel SelectedWorld
|
||||||
private string _banned;
|
|
||||||
public string Banned { get => _banned; set { _banned = value; OnPropertyChanged(); } }
|
|
||||||
private string _mods;
|
|
||||||
public string Mods { get => _mods; set { _mods = value; OnPropertyChanged(); } }
|
|
||||||
|
|
||||||
public int AsteroidAmount
|
|
||||||
{
|
{
|
||||||
get { return _config.AsteroidAmount; }
|
get => _selectedWorld;
|
||||||
set { _config.AsteroidAmount = value; OnPropertyChanged(); }
|
set
|
||||||
|
{
|
||||||
|
SetValue(ref _selectedWorld, value);
|
||||||
|
LoadWorld = _selectedWorld?.WorldPath;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ulong GroupId
|
public List<string> Administrators { get => _config.Administrators; set => SetValue(x => _config.Administrators = x, value); }
|
||||||
{
|
|
||||||
get { return _config.GroupID; }
|
|
||||||
set { _config.GroupID = value; OnPropertyChanged(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public string IP
|
public List<ulong> Banned { get => _config.Banned; set => SetValue(x => _config.Banned = x, value); }
|
||||||
{
|
|
||||||
get { return _config.IP; }
|
|
||||||
set { _config.IP = value; OnPropertyChanged(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public int Port
|
public List<ulong> Reserved { get => _config.Reserved; set => SetValue(x => _config.Reserved = x, value); }
|
||||||
{
|
|
||||||
get { return _config.ServerPort; }
|
|
||||||
set { _config.ServerPort = value; OnPropertyChanged(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public string ServerName
|
private List<ulong> _mods = new List<ulong>();
|
||||||
{
|
public List<ulong> Mods { get => _mods; set => SetValue(x => _mods = x, value); }
|
||||||
get { return _config.ServerName; }
|
|
||||||
set { _config.ServerName = value; OnPropertyChanged(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool PauseGameWhenEmpty
|
public int AsteroidAmount { get => _config.AsteroidAmount; set => SetValue(x => _config.AsteroidAmount = x, value); }
|
||||||
{
|
|
||||||
get { return _config.PauseGameWhenEmpty; }
|
|
||||||
set { _config.PauseGameWhenEmpty = value; OnPropertyChanged(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public string PremadeCheckpointPath
|
public ulong GroupId { get => _config.GroupID; set => SetValue(x => _config.GroupID = x, value); }
|
||||||
{
|
|
||||||
get { return _config.PremadeCheckpointPath; }
|
|
||||||
set { _config.PremadeCheckpointPath = value; OnPropertyChanged(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public string LoadWorld
|
public string IP { get => _config.IP; set => SetValue(x => _config.IP = x, value); }
|
||||||
{
|
|
||||||
get { return _config.LoadWorld; }
|
|
||||||
set { _config.LoadWorld = value; OnPropertyChanged(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public int SteamPort
|
public int Port { get => _config.ServerPort; set => SetValue(x => _config.ServerPort = x, value); }
|
||||||
{
|
|
||||||
get { return _config.SteamPort; }
|
|
||||||
set { _config.SteamPort = value; OnPropertyChanged(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public string WorldName
|
public string ServerName { get => _config.ServerName; set => SetValue(x => _config.ServerName = x, value); }
|
||||||
|
|
||||||
|
public string ServerDescription { get => _config.ServerDescription; set => SetValue(x => _config.ServerDescription = x, value); }
|
||||||
|
|
||||||
|
public bool PauseGameWhenEmpty { get => _config.PauseGameWhenEmpty; set => SetValue(x => _config.PauseGameWhenEmpty = x, value); }
|
||||||
|
|
||||||
|
public bool AutodetectDependencies { get => _config.AutodetectDependencies; set => SetValue(x => _config.AutodetectDependencies = x, value); }
|
||||||
|
|
||||||
|
public string PremadeCheckpointPath { get => _config.PremadeCheckpointPath; set => SetValue(x => _config.PremadeCheckpointPath = x, value); }
|
||||||
|
|
||||||
|
public string LoadWorld { get => _config.LoadWorld; set => SetValue(x => _config.LoadWorld = x, value); }
|
||||||
|
|
||||||
|
public int SteamPort { get => _config.SteamPort; set => SetValue(x => _config.SteamPort = x, value); }
|
||||||
|
|
||||||
|
public string WorldName { get => _config.WorldName; set => SetValue(x => _config.WorldName = x, value); }
|
||||||
|
|
||||||
|
//this is a damn server password. I don't care if this is insecure. Bite me.
|
||||||
|
private string _password;
|
||||||
|
public string Password
|
||||||
{
|
{
|
||||||
get { return _config.WorldName; }
|
get
|
||||||
set { _config.WorldName = value; OnPropertyChanged(); }
|
{
|
||||||
|
if (string.IsNullOrEmpty(_password))
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(_config.ServerPasswordHash))
|
||||||
|
return string.Empty;
|
||||||
|
return "**********";
|
||||||
|
}
|
||||||
|
return _password;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_password = value;
|
||||||
|
if(!string.IsNullOrEmpty(value))
|
||||||
|
_config.SetPassword(value);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_config.ServerPasswordHash = null;
|
||||||
|
_config.ServerPasswordSalt = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -15,10 +15,10 @@ namespace Torch.Server.ViewModels.Blocks
|
|||||||
{
|
{
|
||||||
public class BlockViewModel : EntityViewModel
|
public class BlockViewModel : EntityViewModel
|
||||||
{
|
{
|
||||||
public IMyTerminalBlock Block { get; }
|
public IMyTerminalBlock Block => (IMyTerminalBlock) Entity;
|
||||||
public MtObservableList<PropertyViewModel> Properties { get; } = new MtObservableList<PropertyViewModel>();
|
public MtObservableList<PropertyViewModel> Properties { get; } = new MtObservableList<PropertyViewModel>();
|
||||||
|
|
||||||
public string FullName => $"{Block.CubeGrid.CustomName} - {Block.CustomName}";
|
public string FullName => $"{Block?.CubeGrid.CustomName} - {Block?.CustomName}";
|
||||||
|
|
||||||
public override string Name
|
public override string Name
|
||||||
{
|
{
|
||||||
@@ -38,7 +38,7 @@ namespace Torch.Server.ViewModels.Blocks
|
|||||||
|
|
||||||
public long BuiltBy
|
public long BuiltBy
|
||||||
{
|
{
|
||||||
get => ((MySlimBlock)Block.SlimBlock).BuiltBy;
|
get => ((MySlimBlock)Block?.SlimBlock)?.BuiltBy ?? 0;
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
TorchBase.Instance.Invoke(() =>
|
TorchBase.Instance.Invoke(() =>
|
||||||
@@ -59,7 +59,6 @@ namespace Torch.Server.ViewModels.Blocks
|
|||||||
|
|
||||||
public BlockViewModel(IMyTerminalBlock block, EntityTreeViewModel tree) : base(block, tree)
|
public BlockViewModel(IMyTerminalBlock block, EntityTreeViewModel tree) : base(block, tree)
|
||||||
{
|
{
|
||||||
Block = block;
|
|
||||||
if (Block == null)
|
if (Block == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@@ -6,7 +6,12 @@ namespace Torch.Server.ViewModels.Entities
|
|||||||
{
|
{
|
||||||
public CharacterViewModel(MyCharacter character, EntityTreeViewModel tree) : base(character, tree)
|
public CharacterViewModel(MyCharacter character, EntityTreeViewModel tree) : base(character, tree)
|
||||||
{
|
{
|
||||||
|
character.ControllerInfo.ControlAcquired += (x) => { OnPropertyChanged(nameof(Name)); };
|
||||||
|
character.ControllerInfo.ControlReleased += (x) => { OnPropertyChanged(nameof(Name)); };
|
||||||
|
}
|
||||||
|
|
||||||
|
public CharacterViewModel()
|
||||||
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,7 +1,9 @@
|
|||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
|
using Sandbox.Game.World;
|
||||||
using Torch.API.Managers;
|
using Torch.API.Managers;
|
||||||
using Torch.Collections;
|
using Torch.Collections;
|
||||||
using Torch.Server.Managers;
|
using Torch.Server.Managers;
|
||||||
|
using VRage.Game.Entity;
|
||||||
using VRage.Game.ModAPI;
|
using VRage.Game.ModAPI;
|
||||||
using VRage.ModAPI;
|
using VRage.ModAPI;
|
||||||
using VRageMath;
|
using VRageMath;
|
||||||
@@ -32,23 +34,25 @@ namespace Torch.Server.ViewModels.Entities
|
|||||||
|
|
||||||
public virtual string Name
|
public virtual string Name
|
||||||
{
|
{
|
||||||
get => Entity.DisplayName;
|
get => Entity?.DisplayName ?? (Entity != null ? $"eid:{Entity.EntityId}" : "nil");
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
TorchBase.Instance.InvokeBlocking(() => Entity.DisplayName = value);
|
if (Entity!=null)
|
||||||
|
TorchBase.Instance.InvokeBlocking(() => Entity.DisplayName = value);
|
||||||
OnPropertyChanged();
|
OnPropertyChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual string Position
|
public virtual string Position
|
||||||
{
|
{
|
||||||
get => Entity.GetPosition().ToString();
|
get => Entity?.GetPosition().ToString();
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (!Vector3D.TryParse(value, out Vector3D v))
|
if (!Vector3D.TryParse(value, out Vector3D v))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
TorchBase.Instance.InvokeBlocking(() => Entity.SetPosition(v));
|
if (Entity != null)
|
||||||
|
TorchBase.Instance.InvokeBlocking(() => Entity.SetPosition(v));
|
||||||
OnPropertyChanged();
|
OnPropertyChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,68 +1,117 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using Sandbox.Definitions;
|
||||||
using Sandbox.Game.Entities;
|
using Sandbox.Game.Entities;
|
||||||
|
using Sandbox.Game.Entities.Cube;
|
||||||
using Sandbox.ModAPI;
|
using Sandbox.ModAPI;
|
||||||
using Torch.API.Managers;
|
using Torch.API.Managers;
|
||||||
using Torch.Collections;
|
using Torch.Collections;
|
||||||
using Torch.Server.ViewModels.Blocks;
|
using Torch.Server.ViewModels.Blocks;
|
||||||
|
using VRage.Game;
|
||||||
|
|
||||||
namespace Torch.Server.ViewModels.Entities
|
namespace Torch.Server.ViewModels.Entities
|
||||||
{
|
{
|
||||||
public class GridViewModel : EntityViewModel, ILazyLoad
|
public class GridViewModel : EntityViewModel, ILazyLoad
|
||||||
{
|
{
|
||||||
private MyCubeGrid Grid => (MyCubeGrid)Entity;
|
private static readonly MyCubeBlockDefinition _fillerDefinition = new MyCubeBlockDefinition()
|
||||||
public MtObservableList<BlockViewModel> Blocks { get; } = new MtObservableList<BlockViewModel>();
|
{
|
||||||
|
Id = new MyDefinitionId(typeof(MyObjectBuilder_DefinitionBase), "")
|
||||||
|
};
|
||||||
|
|
||||||
|
private class CubeBlockDefinitionComparer : IComparer<MyCubeBlockDefinition>
|
||||||
|
{
|
||||||
|
public static readonly CubeBlockDefinitionComparer Default = new CubeBlockDefinitionComparer();
|
||||||
|
|
||||||
|
public int Compare(MyCubeBlockDefinition x, MyCubeBlockDefinition y)
|
||||||
|
{
|
||||||
|
if (x == null && y == null)
|
||||||
|
return 0;
|
||||||
|
if (x == null)
|
||||||
|
return -1;
|
||||||
|
if (y == null)
|
||||||
|
return 1;
|
||||||
|
if (ReferenceEquals(x, y))
|
||||||
|
return 0;
|
||||||
|
MyDefinitionId xi = x.Id;
|
||||||
|
MyDefinitionId yi = y.Id;
|
||||||
|
if (xi == yi)
|
||||||
|
return 0;
|
||||||
|
if (xi.TypeId != yi.TypeId)
|
||||||
|
return string.CompareOrdinal(((Type) xi.TypeId).Name, ((Type) yi.TypeId).Name);
|
||||||
|
return xi.SubtypeId == yi.SubtypeId ? 0 : string.CompareOrdinal(xi.SubtypeName, yi.SubtypeName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private MyCubeGrid Grid => (MyCubeGrid) Entity;
|
||||||
|
|
||||||
|
public MtObservableSortedDictionary<MyCubeBlockDefinition, MtObservableSortedDictionary<long, BlockViewModel>>
|
||||||
|
Blocks { get; } =
|
||||||
|
new MtObservableSortedDictionary<MyCubeBlockDefinition, MtObservableSortedDictionary<long, BlockViewModel>>(
|
||||||
|
CubeBlockDefinitionComparer.Default);
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public string DescriptiveName { get; }
|
public string DescriptiveName { get; }
|
||||||
|
|
||||||
public GridViewModel() { }
|
public GridViewModel()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
public GridViewModel(MyCubeGrid grid, EntityTreeViewModel tree) : base(grid, tree)
|
public GridViewModel(MyCubeGrid grid, EntityTreeViewModel tree) : base(grid, tree)
|
||||||
{
|
{
|
||||||
DescriptiveName = $"{grid.DisplayName} ({grid.BlocksCount} blocks)";
|
DescriptiveName = $"{grid.DisplayName} ({grid.BlocksCount} blocks)";
|
||||||
Blocks.Add(new BlockViewModel(null, Tree));
|
Blocks.Add(_fillerDefinition, new MtObservableSortedDictionary<long, BlockViewModel>());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Grid_OnBlockRemoved(Sandbox.Game.Entities.Cube.MySlimBlock obj)
|
private void Grid_OnBlockRemoved(Sandbox.Game.Entities.Cube.MySlimBlock obj)
|
||||||
{
|
{
|
||||||
if (obj.FatBlock != null)
|
if (obj.FatBlock != null)
|
||||||
Blocks.RemoveWhere(b => b.Block.EntityId == obj.FatBlock?.EntityId);
|
RemoveBlock(obj.FatBlock);
|
||||||
|
|
||||||
OnPropertyChanged(nameof(Name));
|
OnPropertyChanged(nameof(Name));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void RemoveBlock(MyCubeBlock block)
|
||||||
|
{
|
||||||
|
if (!Blocks.TryGetValue(block.BlockDefinition, out var group))
|
||||||
|
return;
|
||||||
|
if (group.Remove(block.EntityId) && group.Count == 0 && Blocks.Count > 1)
|
||||||
|
Blocks.Remove(block.BlockDefinition);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddBlock(MyTerminalBlock block)
|
||||||
|
{
|
||||||
|
if (!Blocks.TryGetValue(block.BlockDefinition, out var group))
|
||||||
|
group = Blocks[block.BlockDefinition] = new MtObservableSortedDictionary<long, BlockViewModel>();
|
||||||
|
group.Add(block.EntityId, new BlockViewModel(block, Tree));
|
||||||
|
}
|
||||||
|
|
||||||
private void Grid_OnBlockAdded(Sandbox.Game.Entities.Cube.MySlimBlock obj)
|
private void Grid_OnBlockAdded(Sandbox.Game.Entities.Cube.MySlimBlock obj)
|
||||||
{
|
{
|
||||||
var block = obj.FatBlock as IMyTerminalBlock;
|
var block = obj.FatBlock as MyTerminalBlock;
|
||||||
if (block != null)
|
if (block != null)
|
||||||
Blocks.Add(new BlockViewModel(block, Tree));
|
AddBlock(block);
|
||||||
|
|
||||||
OnPropertyChanged(nameof(Name));
|
OnPropertyChanged(nameof(Name));
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool _load;
|
private bool _load;
|
||||||
|
|
||||||
public void Load()
|
public void Load()
|
||||||
{
|
{
|
||||||
if (_load)
|
if (_load)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_load = true;
|
_load = true;
|
||||||
Blocks.Clear();
|
|
||||||
TorchBase.Instance.Invoke(() =>
|
TorchBase.Instance.Invoke(() =>
|
||||||
{
|
{
|
||||||
foreach (var block in Grid.GetFatBlocks().Where(b => b is IMyTerminalBlock))
|
Blocks.Clear();
|
||||||
{
|
foreach (var block in Grid.GetFatBlocks().OfType<MyTerminalBlock>())
|
||||||
Blocks.Add(new BlockViewModel((IMyTerminalBlock)block, Tree));
|
AddBlock(block);
|
||||||
}
|
|
||||||
|
|
||||||
Grid.OnBlockAdded += Grid_OnBlockAdded;
|
Grid.OnBlockAdded += Grid_OnBlockAdded;
|
||||||
Grid.OnBlockRemoved += Grid_OnBlockRemoved;
|
Grid.OnBlockRemoved += Grid_OnBlockRemoved;
|
||||||
|
|
||||||
Tree.ControlDispatcher.BeginInvoke(() =>
|
|
||||||
{
|
|
||||||
Blocks.Sort(b => b.Block.CustomName);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -29,11 +29,10 @@ namespace Torch.Server.ViewModels.Entities
|
|||||||
await TorchBase.Instance.InvokeAsync(() => MyEntities.GetTopMostEntitiesInBox(ref box, entities)).ConfigureAwait(false);
|
await TorchBase.Instance.InvokeAsync(() => MyEntities.GetTopMostEntitiesInBox(ref box, entities)).ConfigureAwait(false);
|
||||||
foreach (var entity in entities.Where(e => e is IMyCubeGrid))
|
foreach (var entity in entities.Where(e => e is IMyCubeGrid))
|
||||||
{
|
{
|
||||||
var gridModel = Tree.Grids.FirstOrDefault(g => g.Entity.EntityId == entity.EntityId);
|
if (Tree.Grids.TryGetValue(entity.EntityId, out var gridModel))
|
||||||
if (gridModel == null)
|
|
||||||
{
|
{
|
||||||
gridModel = new GridViewModel((MyCubeGrid)entity, Tree);
|
gridModel = new GridViewModel((MyCubeGrid)entity, Tree);
|
||||||
Tree.Grids.Add(gridModel);
|
Tree.Grids.Add(entity.EntityId, gridModel);
|
||||||
}
|
}
|
||||||
|
|
||||||
AttachedGrids.Add(gridModel);
|
AttachedGrids.Add(gridModel);
|
||||||
|
@@ -20,10 +20,10 @@ namespace Torch.Server.ViewModels
|
|||||||
private static readonly Logger _log = LogManager.GetCurrentClassLogger();
|
private static readonly Logger _log = LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
//TODO: these should be sorted sets for speed
|
//TODO: these should be sorted sets for speed
|
||||||
public MtObservableList<GridViewModel> Grids { get; set; } = new MtObservableList<GridViewModel>();
|
public MtObservableSortedDictionary<long, GridViewModel> Grids { get; set; } = new MtObservableSortedDictionary<long, GridViewModel>();
|
||||||
public MtObservableList<CharacterViewModel> Characters { get; set; } = new MtObservableList<CharacterViewModel>();
|
public MtObservableSortedDictionary<long, CharacterViewModel> Characters { get; set; } = new MtObservableSortedDictionary<long, CharacterViewModel>();
|
||||||
public MtObservableList<EntityViewModel> FloatingObjects { get; set; } = new MtObservableList<EntityViewModel>();
|
public MtObservableSortedDictionary<long, EntityViewModel> FloatingObjects { get; set; } = new MtObservableSortedDictionary<long, EntityViewModel>();
|
||||||
public MtObservableList<VoxelMapViewModel> VoxelMaps { get; set; } = new MtObservableList<VoxelMapViewModel>();
|
public MtObservableSortedDictionary<long, VoxelMapViewModel> VoxelMaps { get; set; } = new MtObservableSortedDictionary<long, VoxelMapViewModel>();
|
||||||
public Dispatcher ControlDispatcher => _control.Dispatcher;
|
public Dispatcher ControlDispatcher => _control.Dispatcher;
|
||||||
|
|
||||||
private EntityViewModel _currentEntity;
|
private EntityViewModel _currentEntity;
|
||||||
@@ -35,6 +35,11 @@ namespace Torch.Server.ViewModels
|
|||||||
set { _currentEntity = value; OnPropertyChanged(nameof(CurrentEntity)); }
|
set { _currentEntity = value; OnPropertyChanged(nameof(CurrentEntity)); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// I hate you today WPF
|
||||||
|
public EntityTreeViewModel() : this(null)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
public EntityTreeViewModel(UserControl control)
|
public EntityTreeViewModel(UserControl control)
|
||||||
{
|
{
|
||||||
_control = control;
|
_control = control;
|
||||||
@@ -53,16 +58,16 @@ namespace Torch.Server.ViewModels
|
|||||||
switch (obj)
|
switch (obj)
|
||||||
{
|
{
|
||||||
case MyCubeGrid grid:
|
case MyCubeGrid grid:
|
||||||
Grids.RemoveWhere(m => m.Id == grid.EntityId);
|
Grids.Remove(grid.EntityId);
|
||||||
break;
|
break;
|
||||||
case MyCharacter character:
|
case MyCharacter character:
|
||||||
Characters.RemoveWhere(m => m.Id == character.EntityId);
|
Characters.Remove(character.EntityId);
|
||||||
break;
|
break;
|
||||||
case MyFloatingObject floating:
|
case MyFloatingObject floating:
|
||||||
FloatingObjects.RemoveWhere(m => m.Id == floating.EntityId);
|
FloatingObjects.Remove(floating.EntityId);
|
||||||
break;
|
break;
|
||||||
case MyVoxelBase voxel:
|
case MyVoxelBase voxel:
|
||||||
VoxelMaps.RemoveWhere(m => m.Id == voxel.EntityId);
|
VoxelMaps.Remove(voxel.EntityId);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -80,16 +85,16 @@ namespace Torch.Server.ViewModels
|
|||||||
switch (obj)
|
switch (obj)
|
||||||
{
|
{
|
||||||
case MyCubeGrid grid:
|
case MyCubeGrid grid:
|
||||||
Grids.Add(new GridViewModel(grid, this));
|
Grids.Add(obj.EntityId, new GridViewModel(grid, this));
|
||||||
break;
|
break;
|
||||||
case MyCharacter character:
|
case MyCharacter character:
|
||||||
Characters.Add(new CharacterViewModel(character, this));
|
Characters.Add(obj.EntityId, new CharacterViewModel(character, this));
|
||||||
break;
|
break;
|
||||||
case MyFloatingObject floating:
|
case MyFloatingObject floating:
|
||||||
FloatingObjects.Add(new FloatingObjectViewModel(floating, this));
|
FloatingObjects.Add(obj.EntityId, new FloatingObjectViewModel(floating, this));
|
||||||
break;
|
break;
|
||||||
case MyVoxelBase voxel:
|
case MyVoxelBase voxel:
|
||||||
VoxelMaps.Add(new VoxelMapViewModel(voxel, this));
|
VoxelMaps.Add(obj.EntityId, new VoxelMapViewModel(voxel, this));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -3,32 +3,40 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
using Torch.API;
|
using Torch.API;
|
||||||
using Torch.API.Plugins;
|
using Torch.API.Plugins;
|
||||||
|
using Torch.Server.Views;
|
||||||
|
|
||||||
namespace Torch.Server.ViewModels
|
namespace Torch.Server.ViewModels
|
||||||
{
|
{
|
||||||
public class PluginViewModel
|
public class PluginViewModel
|
||||||
{
|
{
|
||||||
public UserControl Control
|
public UserControl Control { get; }
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (Plugin is IWpfPlugin p)
|
|
||||||
return p.GetControl();
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public string Name { get; }
|
public string Name { get; }
|
||||||
public ITorchPlugin Plugin { get; }
|
public ITorchPlugin Plugin { get; }
|
||||||
|
|
||||||
public PluginViewModel(ITorchPlugin plugin)
|
public PluginViewModel(ITorchPlugin plugin)
|
||||||
{
|
{
|
||||||
Plugin = plugin;
|
Plugin = plugin;
|
||||||
|
|
||||||
|
if (Plugin is IWpfPlugin p)
|
||||||
|
Control = p.GetControl();
|
||||||
|
|
||||||
Name = $"{plugin.Name} ({plugin.Version})";
|
Name = $"{plugin.Name} ({plugin.Version})";
|
||||||
|
|
||||||
|
ThemeControl.UpdateDynamicControls += UpdateResourceDict;
|
||||||
|
UpdateResourceDict(ThemeControl.currentTheme);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateResourceDict(ResourceDictionary dictionary)
|
||||||
|
{
|
||||||
|
if (this.Control == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this.Control.Resources.MergedDictionaries.Clear();
|
||||||
|
this.Control.Resources.MergedDictionaries.Add(dictionary);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,387 +1,267 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.ObjectModel;
|
using System.ComponentModel;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using Torch;
|
||||||
using System.Threading.Tasks;
|
|
||||||
using SharpDX.Toolkit.Collections;
|
|
||||||
using Torch.Collections;
|
using Torch.Collections;
|
||||||
|
using Torch.Views;
|
||||||
using VRage.Game;
|
using VRage.Game;
|
||||||
using VRage.Library.Utils;
|
using VRage.Library.Utils;
|
||||||
|
using VRage.Serialization;
|
||||||
|
|
||||||
namespace Torch.Server.ViewModels
|
namespace Torch.Server.ViewModels
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// View model for <see cref="MyObjectBuilder_SessionSettings"/>
|
|
||||||
/// </summary>
|
|
||||||
public class SessionSettingsViewModel : ViewModel
|
public class SessionSettingsViewModel : ViewModel
|
||||||
{
|
{
|
||||||
private MyObjectBuilder_SessionSettings _settings;
|
private MyObjectBuilder_SessionSettings _settings;
|
||||||
|
|
||||||
/// <summary>
|
[Torch.Views.Display(Description = "The type of the game mode.", Name = "Game Mode", GroupName = "Others")]
|
||||||
/// Creates a new view model with a new <see cref="MyObjectBuilder_SessionSettings"/> object.
|
public MyGameModeEnum GameMode { get => _settings.GameMode; set => SetValue(ref _settings.GameMode, value); }
|
||||||
/// </summary>
|
[Torch.Views.Display(Description = "The type of the game online mode.", Name = "Online Mode", GroupName = "Others")]
|
||||||
public SessionSettingsViewModel() : this(new MyObjectBuilder_SessionSettings())
|
public MyOnlineModeEnum OnlineMode { get => _settings.OnlineMode; set => SetValue(ref _settings.OnlineMode, value); }
|
||||||
{
|
|
||||||
|
|
||||||
}
|
[Torch.Views.Display(Description = "The multiplier for inventory size.", Name = "Inventory Size", GroupName = "Multipliers")]
|
||||||
|
public float InventorySizeMultiplier { get => _settings.InventorySizeMultiplier; set => SetValue(ref _settings.InventorySizeMultiplier, value); }
|
||||||
|
|
||||||
|
[Torch.Views.Display(Description = "The multiplier for assembler speed.", Name = "Assembler Speed", GroupName = "Multipliers")]
|
||||||
|
public float AssemblerSpeedMultiplier { get => _settings.AssemblerSpeedMultiplier; set => SetValue(ref _settings.AssemblerSpeedMultiplier, value); }
|
||||||
|
|
||||||
|
[Torch.Views.Display(Description = "The multiplier for assembler efficiency.", Name = "Assembler Efficiency", GroupName = "Multipliers")]
|
||||||
|
public float AssemblerEfficiencyMultiplier { get => _settings.AssemblerEfficiencyMultiplier; set => SetValue(ref _settings.AssemblerEfficiencyMultiplier, value); }
|
||||||
|
|
||||||
|
[Torch.Views.Display(Description = "The multiplier for refinery speed.", Name = "Refinery Speed", GroupName = "Multipliers")]
|
||||||
|
public float RefinerySpeedMultiplier { get => _settings.RefinerySpeedMultiplier; set => SetValue(ref _settings.RefinerySpeedMultiplier, value); }
|
||||||
|
|
||||||
|
[Torch.Views.Display(Description = "The maximum number of connected players.", Name = "Max Players", GroupName = "Players")]
|
||||||
|
public short MaxPlayers { get => _settings.MaxPlayers; set => SetValue(ref _settings.MaxPlayers, value); }
|
||||||
|
|
||||||
|
[Torch.Views.Display(Description = "The maximum number of existing floating objects.", Name = "Max Floating Objects", GroupName = "Environment")]
|
||||||
|
public short MaxFloatingObjects { get => _settings.MaxFloatingObjects; set => SetValue(ref _settings.MaxFloatingObjects, value); }
|
||||||
|
|
||||||
|
[Torch.Views.Display(Description = "The maximum number of backup saves.", Name = "Max Backup Saves", GroupName = "Others")]
|
||||||
|
public short MaxBackupSaves { get => _settings.MaxBackupSaves; set => SetValue(ref _settings.MaxBackupSaves, value); }
|
||||||
|
|
||||||
|
[Torch.Views.Display(Description = "The maximum number of blocks in one grid.", Name = "Max Grid Blocks", GroupName = "Block Limits")]
|
||||||
|
public int MaxGridSize { get => _settings.MaxGridSize; set => SetValue(ref _settings.MaxGridSize, value); }
|
||||||
|
|
||||||
|
[Torch.Views.Display(Description = "The maximum number of blocks per player.", Name = "Max Blocks per Player", GroupName = "Block Limits")]
|
||||||
|
public int MaxBlocksPerPlayer { get => _settings.MaxBlocksPerPlayer; set => SetValue(ref _settings.MaxBlocksPerPlayer, value); }
|
||||||
|
|
||||||
|
[Torch.Views.Display(Description = "The total number of Performance Cost Units in the world.", Name = "World PCU", GroupName = "Block Limits")]
|
||||||
|
public int TotalPCU { get => _settings.TotalPCU; set => SetValue(ref _settings.TotalPCU, value); }
|
||||||
|
|
||||||
|
[Torch.Views.Display(Description = "The maximum number of existing factions in the world.", Name = "Max Factions Count", GroupName = "Block Limits")]
|
||||||
|
public int MaxFactionsCount { get => _settings.MaxFactionsCount; set => SetValue(ref _settings.MaxFactionsCount, value); }
|
||||||
|
|
||||||
|
[Torch.Views.Display(Description = "Defines block limits mode.", Name = "Block Limits Mode", GroupName = "Block Limits")]
|
||||||
|
public MyBlockLimitsEnabledEnum BlockLimitsEnabled { get => _settings.BlockLimitsEnabled; set => SetValue(ref _settings.BlockLimitsEnabled, value); }
|
||||||
|
|
||||||
|
[Torch.Views.Display(Description = "Enables possibility to remove grid remotely from the world by an author.", Name = "Enable Remote Grid Removal", GroupName = "Others")]
|
||||||
|
public bool EnableRemoteBlockRemoval { get => _settings.EnableRemoteBlockRemoval; set => SetValue(ref _settings.EnableRemoteBlockRemoval, value); }
|
||||||
|
|
||||||
|
[Torch.Views.Display(Description = "Defines hostility of the environment.", Name = "Environment Hostility", GroupName = "Environment")]
|
||||||
|
public MyEnvironmentHostilityEnum EnvironmentHostility { get => _settings.EnvironmentHostility; set => SetValue(ref _settings.EnvironmentHostility, value); }
|
||||||
|
|
||||||
|
[Torch.Views.Display(Description = "Enables auto healing of the character.", Name = "Auto Healing", GroupName = "Players")]
|
||||||
|
public bool AutoHealing { get => _settings.AutoHealing; set => SetValue(ref _settings.AutoHealing, value); }
|
||||||
|
|
||||||
|
[Torch.Views.Display(Description = "Enables copy and paste feature.", Name = "Enable Copy & Paste", GroupName = "Players")]
|
||||||
|
public bool EnableCopyPaste { get => _settings.EnableCopyPaste; set => SetValue(ref _settings.EnableCopyPaste, value); }
|
||||||
|
|
||||||
|
[Torch.Views.Display(Description = "Enables weapons.", Name = "Enable Weapons", GroupName = "Others")]
|
||||||
|
public bool WeaponsEnabled { get => _settings.WeaponsEnabled; set => SetValue(ref _settings.WeaponsEnabled, value); }
|
||||||
|
|
||||||
|
[Torch.Views.Display(Description = "", Name = "Show Player Names on HUD", GroupName = "Players")]
|
||||||
|
public bool ShowPlayerNamesOnHud { get => _settings.ShowPlayerNamesOnHud; set => SetValue(ref _settings.ShowPlayerNamesOnHud, value); }
|
||||||
|
|
||||||
|
[Torch.Views.Display(Description = "Enables thruster damage.", Name = "Enable Thruster Damage", GroupName = "Others")]
|
||||||
|
public bool ThrusterDamage { get => _settings.ThrusterDamage; set => SetValue(ref _settings.ThrusterDamage, value); }
|
||||||
|
|
||||||
|
[Torch.Views.Display(Description = "Enables spawning of cargo ships.", Name = "Enable Cargo Ships", GroupName = "NPCs")]
|
||||||
|
public bool CargoShipsEnabled { get => _settings.CargoShipsEnabled; set => SetValue(ref _settings.CargoShipsEnabled, value); }
|
||||||
|
|
||||||
|
[Torch.Views.Display(Description = "Enables spectator camera.", Name = "Enable Spectator Camera", GroupName = "Others")]
|
||||||
|
public bool EnableSpectator { get => _settings.EnableSpectator; set => SetValue(ref _settings.EnableSpectator, value); }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a view model using an existing <see cref="MyObjectBuilder_SessionSettings"/> object.
|
/// Size of the edge of the world area cube.
|
||||||
|
/// Don't use directly, as it is error-prone (it's km instead of m and edge size instead of half-extent)
|
||||||
|
/// Rather use MyEntities.WorldHalfExtent()
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[Torch.Views.Display(Description = "Defines the size of the world.", Name = "World Size [km]", GroupName = "Environment")]
|
||||||
|
public int WorldSizeKm { get => _settings.WorldSizeKm; set => SetValue(ref _settings.WorldSizeKm, value); }
|
||||||
|
|
||||||
|
[Torch.Views.Display(Description = "When enabled respawn ship is removed after player logout.", Name = "Remove Respawn Ships on Logoff", GroupName = "Others")]
|
||||||
|
public bool RespawnShipDelete { get => _settings.RespawnShipDelete; set => SetValue(ref _settings.RespawnShipDelete, value); }
|
||||||
|
|
||||||
|
[Torch.Views.Display(Description = "", Name = "Reset Ownership", GroupName = "Players")]
|
||||||
|
public bool ResetOwnership { get => _settings.ResetOwnership; set => SetValue(ref _settings.ResetOwnership, value); }
|
||||||
|
|
||||||
|
[Torch.Views.Display(Description = "The multiplier for welder speed.", Name = "Welder Speed", GroupName = "Multipliers")]
|
||||||
|
public float WelderSpeedMultiplier { get => _settings.WelderSpeedMultiplier; set => SetValue(ref _settings.WelderSpeedMultiplier, value); }
|
||||||
|
|
||||||
|
[Torch.Views.Display(Description = "The multiplier for grinder speed.", Name = "Grinder Speed", GroupName = "Multipliers")]
|
||||||
|
public float GrinderSpeedMultiplier { get => _settings.GrinderSpeedMultiplier; set => SetValue(ref _settings.GrinderSpeedMultiplier, value); }
|
||||||
|
|
||||||
|
[Torch.Views.Display(Description = "Enables realistic sounds.", Name = "Enable Realistic Sound", GroupName = "Environment")]
|
||||||
|
public bool RealisticSound { get => _settings.RealisticSound; set => SetValue(ref _settings.RealisticSound, value); }
|
||||||
|
|
||||||
|
[Torch.Views.Display(Description = "The multiplier for hacking speed.", Name = "Hacking Speed", GroupName = "Multipliers")]
|
||||||
|
public float HackSpeedMultiplier { get => _settings.HackSpeedMultiplier; set => SetValue(ref _settings.HackSpeedMultiplier, value); }
|
||||||
|
|
||||||
|
[Torch.Views.Display(Description = "Enables permanent death.", Name = "Permanent Death", GroupName = "Players")]
|
||||||
|
public bool? PermanentDeath { get => _settings.PermanentDeath; set => SetValue(ref _settings.PermanentDeath, value); }
|
||||||
|
|
||||||
|
[Torch.Views.Display(Description = "Defines autosave interval.", Name = "Autosave Interval [mins]", GroupName = "Others")]
|
||||||
|
public uint AutoSaveInMinutes { get => _settings.AutoSaveInMinutes; set => SetValue(ref _settings.AutoSaveInMinutes, value); }
|
||||||
|
|
||||||
|
[Torch.Views.Display(Description = "Enables saving from the menu.", Name = "Enable Saving from Menu", GroupName = "Others")]
|
||||||
|
public bool EnableSaving { get => _settings.EnableSaving; set => SetValue(ref _settings.EnableSaving, value); }
|
||||||
|
|
||||||
|
[Torch.Views.Display(Description = "Enables respawn screen.", Name = "Enable Respawn Screen in the Game", GroupName = "Players")]
|
||||||
|
public bool EnableRespawnScreen { get => _settings.EnableRespawnScreen; set => SetValue(ref _settings.EnableRespawnScreen, value); }
|
||||||
|
|
||||||
|
[Torch.Views.Display(Description = "Enables infinite ammunition in survival game mode.", Name = "Enable Infinite Ammunition in Survival", GroupName = "Others")]
|
||||||
|
public bool InfiniteAmmo { get => _settings.InfiniteAmmo; set => SetValue(ref _settings.InfiniteAmmo, value); }
|
||||||
|
|
||||||
|
[Torch.Views.Display(Description = "Enables drop containers (unknown signals).", Name = "Enable Drop Containers", GroupName = "Others")]
|
||||||
|
public bool EnableContainerDrops { get => _settings.EnableContainerDrops; set => SetValue(ref _settings.EnableContainerDrops, value); }
|
||||||
|
|
||||||
|
[Torch.Views.Display(Description = "The multiplier for respawn ship timer.", Name = "Respawn Ship Time Multiplier", GroupName = "Players")]
|
||||||
|
public float SpawnShipTimeMultiplier { get => _settings.SpawnShipTimeMultiplier; set => SetValue(ref _settings.SpawnShipTimeMultiplier, value); }
|
||||||
|
|
||||||
|
[Torch.Views.Display(Description = "Defines density of the procedurally generated content.", Name = "Procedural Density", GroupName = "Environment")]
|
||||||
|
public float ProceduralDensity { get => _settings.ProceduralDensity; set => SetValue(ref _settings.ProceduralDensity, value); }
|
||||||
|
|
||||||
|
[Torch.Views.Display(Description = "Defines unique starting seed for the procedurally generated content.", Name = "Procedural Seed", GroupName = "Environment")]
|
||||||
|
public int ProceduralSeed { get => _settings.ProceduralSeed; set => SetValue(ref _settings.ProceduralSeed, value); }
|
||||||
|
|
||||||
|
[Torch.Views.Display(Description = "Enables destruction feature for the blocks.", Name = "Enable Destructible Blocks", GroupName = "Environment")]
|
||||||
|
public bool DestructibleBlocks { get => _settings.DestructibleBlocks; set => SetValue(ref _settings.DestructibleBlocks, value); }
|
||||||
|
|
||||||
|
[Torch.Views.Display(Description = "Enables in game scripts.", Name = "Enable Ingame Scripts", GroupName = "Others")]
|
||||||
|
public bool EnableIngameScripts { get => _settings.EnableIngameScripts; set => SetValue(ref _settings.EnableIngameScripts, value); }
|
||||||
|
|
||||||
|
[Torch.Views.Display(Description = "", Name = "Flora Density Multiplier", GroupName = "Environment")]
|
||||||
|
public float FloraDensityMultiplier { get => _settings.FloraDensityMultiplier; set => SetValue(ref _settings.FloraDensityMultiplier, value); }
|
||||||
|
|
||||||
|
[Torch.Views.Display(Description = "Enables tool shake feature.", Name = "Enable Tool Shake", GroupName = "Players")]
|
||||||
|
[DefaultValue(false)]
|
||||||
|
public bool EnableToolShake { get => _settings.EnableToolShake; set => SetValue(ref _settings.EnableToolShake, value); }
|
||||||
|
|
||||||
|
[Torch.Views.Display(Description = "", Name = "Voxel Generator Version", GroupName = "Environment")]
|
||||||
|
public int VoxelGeneratorVersion { get => _settings.VoxelGeneratorVersion; set => SetValue(ref _settings.VoxelGeneratorVersion, value); }
|
||||||
|
|
||||||
|
[Torch.Views.Display(Description = "Enables oxygen in the world.", Name = "Enable Oxygen", GroupName = "Environment")]
|
||||||
|
public bool EnableOxygen { get => _settings.EnableOxygen; set => SetValue(ref _settings.EnableOxygen, value); }
|
||||||
|
|
||||||
|
[Torch.Views.Display(Description = "Enables airtightness in the world.", Name = "Enable Airtightness", GroupName = "Environment")]
|
||||||
|
public bool EnableOxygenPressurization { get => _settings.EnableOxygenPressurization; set => SetValue(ref _settings.EnableOxygenPressurization, value); }
|
||||||
|
|
||||||
|
[Torch.Views.Display(Description = "Enables 3rd person camera.", Name = "Enable 3rd Person Camera", GroupName = "Players")]
|
||||||
|
public bool Enable3rdPersonView { get => _settings.Enable3rdPersonView; set => SetValue(ref _settings.Enable3rdPersonView, value); }
|
||||||
|
|
||||||
|
[Torch.Views.Display(Description = "Enables random encounters in the world.", Name = "Enable Encounters", GroupName = "NPCs")]
|
||||||
|
public bool EnableEncounters { get => _settings.EnableEncounters; set => SetValue(ref _settings.EnableEncounters, value); }
|
||||||
|
|
||||||
|
[Torch.Views.Display(Description = "Enables possibility of converting grid to station.", Name = "Enable Convert to Station", GroupName = "Others")]
|
||||||
|
public bool EnableConvertToStation { get => _settings.EnableConvertToStation; set => SetValue(ref _settings.EnableConvertToStation, value); }
|
||||||
|
|
||||||
|
[Torch.Views.Display(Description = "Enables possibility of station grid inside voxel.", Name = "Enable Station Grid with Voxel", GroupName = "Environment")]
|
||||||
|
public bool StationVoxelSupport { get => _settings.StationVoxelSupport; set => SetValue(ref _settings.StationVoxelSupport, value); }
|
||||||
|
|
||||||
|
[Torch.Views.Display(Description = "Enables sun rotation.", Name = "Enable Sun Rotation", GroupName = "Environment")]
|
||||||
|
public bool EnableSunRotation { get => _settings.EnableSunRotation; set => SetValue(ref _settings.EnableSunRotation, value); }
|
||||||
|
|
||||||
|
[Torch.Views.Display(Description = "Enables respawn ships.", Name = "Enable Respawn Ships", GroupName = "Others")]
|
||||||
|
public bool EnableRespawnShips { get => _settings.EnableRespawnShips; set => SetValue(ref _settings.EnableRespawnShips, value); }
|
||||||
|
|
||||||
|
[Torch.Views.Display(Description = "", Name = "Physics Iterations", GroupName = "Environment")]
|
||||||
|
public int PhysicsIterations { get => _settings.PhysicsIterations; set => SetValue(ref _settings.PhysicsIterations, value); }
|
||||||
|
|
||||||
|
[Torch.Views.Display(Description = "Defines interval of one rotation of the sun.", Name = "Sun Rotation Interval", GroupName = "Environment")]
|
||||||
|
public float SunRotationIntervalMinutes { get => _settings.SunRotationIntervalMinutes; set => SetValue(ref _settings.SunRotationIntervalMinutes, value); }
|
||||||
|
|
||||||
|
[Torch.Views.Display(Description = "Enables jetpack.", Name = "Enable Jetpack", GroupName = "Players")]
|
||||||
|
public bool EnableJetpack { get => _settings.EnableJetpack; set => SetValue(ref _settings.EnableJetpack, value); }
|
||||||
|
|
||||||
|
[Torch.Views.Display(Description = "Enables spawning with tools in the inventory.", Name = "Spawn with Tools", GroupName = "Players")]
|
||||||
|
public bool SpawnWithTools { get => _settings.SpawnWithTools; set => SetValue(ref _settings.SpawnWithTools, value); }
|
||||||
|
|
||||||
|
[Torch.Views.Display(Description = "Enables voxel destructions.", Name = "Enable Voxel Destruction", GroupName = "Environment")]
|
||||||
|
public bool EnableVoxelDestruction { get => _settings.EnableVoxelDestruction; set => SetValue(ref _settings.EnableVoxelDestruction, value); }
|
||||||
|
|
||||||
|
[Torch.Views.Display(Description = "Enables spawning of drones in the world.", Name = "Enable Drones", GroupName = "NPCs")]
|
||||||
|
public bool EnableDrones { get => _settings.EnableDrones; set => SetValue(ref _settings.EnableDrones, value); }
|
||||||
|
|
||||||
|
[Torch.Views.Display(Description = "Enables spawning of wolves in the world.", Name = "Enable Wolves", GroupName = "NPCs")]
|
||||||
|
public bool EnableWolfs { get => _settings.EnableWolfs; set => SetValue(ref _settings.EnableWolfs, value); }
|
||||||
|
|
||||||
|
[Torch.Views.Display(Description = "Enables spawning of spiders in the world.", Name = "Enable Spiders", GroupName = "NPCs")]
|
||||||
|
public bool EnableSpiders { get => _settings.EnableSpiders; set => SetValue(ref _settings.EnableSpiders, value); }
|
||||||
|
|
||||||
|
[Torch.Views.Display(Name = "Block Type World Limits", GroupName = "Block Limits")]
|
||||||
|
public Dictionary<string, short> BlockTypeLimits { get => _settings.BlockTypeLimits.Dictionary; set => SetValue(x => _settings.BlockTypeLimits.Dictionary = x, value); }
|
||||||
|
|
||||||
|
[Torch.Views.Display(Description = "Enables scripter role for administration.", Name = "Enable Scripter Role", GroupName = "Others")]
|
||||||
|
public bool EnableScripterRole { get => _settings.EnableScripterRole; set => SetValue(ref _settings.EnableScripterRole, value); }
|
||||||
|
|
||||||
|
[Torch.Views.Display(Description = "Defines minimum respawn time for drop containers.", Name = "Min Drop Container Respawn Time", GroupName = "Others")]
|
||||||
|
public int MinDropContainerRespawnTime { get => _settings.MinDropContainerRespawnTime; set => SetValue(ref _settings.MinDropContainerRespawnTime, value); }
|
||||||
|
|
||||||
|
[Torch.Views.Display(Description = "Defines maximum respawn time for drop containers.", Name = "Max Drop Container Respawn Time", GroupName = "Others")]
|
||||||
|
public int MaxDropContainerRespawnTime { get => _settings.MaxDropContainerRespawnTime; set => SetValue(ref _settings.MaxDropContainerRespawnTime, value); }
|
||||||
|
|
||||||
|
[Torch.Views.Display(Description = "Enables friendly fire for turrets.", Name = "Enable Turrets Friendly Fire", GroupName = "Environment")]
|
||||||
|
public bool EnableTurretsFriendlyFire { get => _settings.EnableTurretsFriendlyFire; set => SetValue(ref _settings.EnableTurretsFriendlyFire, value); }
|
||||||
|
|
||||||
|
[Torch.Views.Display(Description = "Enables sub-grid damage.", Name = "Enable Sub-Grid Damage", GroupName = "Environment")]
|
||||||
|
public bool EnableSubgridDamage { get => _settings.EnableSubgridDamage; set => SetValue(ref _settings.EnableSubgridDamage, value); }
|
||||||
|
|
||||||
|
[Torch.Views.Display(Description = "Defines synchronization distance in multiplayer. High distance can slow down server drastically. Use with caution.", Name = "Sync Distance", GroupName = "Environment")]
|
||||||
|
public int SyncDistance { get => _settings.SyncDistance; set => SetValue(ref _settings.SyncDistance, value); }
|
||||||
|
|
||||||
|
[Torch.Views.Display(Description = "Defines render distance for clients in multiplayer. High distance can slow down client FPS. Values larger than SyncDistance may not work as expected.", Name = "View Distance", GroupName = "Environment")]
|
||||||
|
public int ViewDistance { get => _settings.ViewDistance; set => SetValue(ref _settings.ViewDistance, value);}
|
||||||
|
|
||||||
|
[Torch.Views.Display(Description = "Enables experimental mode.", Name = "Experimental Mode", GroupName = "Others")]
|
||||||
|
public bool ExperimentalMode { get => _settings.ExperimentalMode; set => SetValue(ref _settings.ExperimentalMode, value); }
|
||||||
|
|
||||||
|
[Torch.Views.Display(Description = "Enables adaptive simulation quality system. This system is useful if you have a lot of voxel deformations in the world and low simulation speed.", Name = "Adaptive Simulation Quality", GroupName = "Others")]
|
||||||
|
public bool AdaptiveSimulationQuality { get => _settings.AdaptiveSimulationQuality; set => SetValue(ref _settings.AdaptiveSimulationQuality, value); }
|
||||||
|
|
||||||
|
[Torch.Views.Display(Description = "Enables voxel hand.", Name = "Enable voxel hand", GroupName = "Others")]
|
||||||
|
public bool EnableVoxelHand { get => _settings.EnableVoxelHand; set => SetValue(ref _settings.EnableVoxelHand, value); }
|
||||||
|
|
||||||
|
[Torch.Views.Display(Description = "Enables trash removal system.", Name = "Trash Removal Enabled", GroupName = "Trash Removal")]
|
||||||
|
public bool TrashRemovalEnabled { get => _settings.TrashRemovalEnabled; set => SetValue(ref _settings.TrashRemovalEnabled, value); }
|
||||||
|
|
||||||
|
[Torch.Views.Display(Description = "Defines flags for trash removal system.", Name = "Trash Removal Flags", GroupName = "Trash Removal")]
|
||||||
|
public MyTrashRemovalFlags TrashFlagsValue { get => (MyTrashRemovalFlags)_settings.TrashFlagsValue; set => SetValue(ref _settings.TrashFlagsValue, (int)value); }
|
||||||
|
|
||||||
|
[Torch.Views.Display(Description = "Defines block count threshold for trash removal system.", Name = "Block Count Threshold", GroupName = "Trash Removal")]
|
||||||
|
public int BlockCountThreshold { get => _settings.BlockCountThreshold; set => SetValue(ref _settings.BlockCountThreshold, value); }
|
||||||
|
|
||||||
|
[Torch.Views.Display(Description = "Defines player distance threshold for trash removal system.", Name = "Player Distance Threshold [m]", GroupName = "Trash Removal")]
|
||||||
|
public float PlayerDistanceThreshold { get => _settings.PlayerDistanceThreshold; set => SetValue(ref _settings.PlayerDistanceThreshold, value); }
|
||||||
|
|
||||||
|
[Torch.Views.Display(Description = "By setting this, server will keep number of grids around this value. \n !WARNING! It ignores Powered and Fixed flags, Block Count and lowers Distance from player.\n Set to 0 to disable.", Name = "Optimal Grid Count", GroupName = "Trash Removal")]
|
||||||
|
public int OptimalGridCount { get => _settings.OptimalGridCount; set => SetValue(ref _settings.OptimalGridCount, value); }
|
||||||
|
|
||||||
|
[Torch.Views.Display(Description = "Defines player inactivity threshold for trash removal system. \n !WARNING! This will remove all grids of the player.\n Set to 0 to disable.", Name = "Player Inactivity Threshold [hours]", GroupName = "Trash Removal")]
|
||||||
|
public float PlayerInactivityThreshold { get => _settings.PlayerInactivityThreshold; set => SetValue(ref _settings.PlayerInactivityThreshold, value); }
|
||||||
|
|
||||||
|
[Torch.Views.Display(Description = "Defines character removal threshold for trash removal system. If player disconnects it will remove his character after this time.\n Set to 0 to disable.", Name = "Character Removal Threshold [mins]", GroupName = "Trash Removal")]
|
||||||
|
public int PlayerCharacterRemovalThreshold { get => _settings.PlayerCharacterRemovalThreshold; set => SetValue(ref _settings.PlayerCharacterRemovalThreshold, value); }
|
||||||
|
|
||||||
public SessionSettingsViewModel(MyObjectBuilder_SessionSettings settings)
|
public SessionSettingsViewModel(MyObjectBuilder_SessionSettings settings)
|
||||||
{
|
{
|
||||||
_settings = settings;
|
_settings = settings;
|
||||||
foreach (var limit in settings.BlockTypeLimits.Dictionary)
|
|
||||||
BlockLimits.Add(new BlockLimitViewModel(this, limit.Key, limit.Value));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public MtObservableList<BlockLimitViewModel> BlockLimits { get; } = new MtObservableList<BlockLimitViewModel>();
|
|
||||||
|
|
||||||
#region Multipliers
|
|
||||||
|
|
||||||
/// <inheritdoc cref="MyObjectBuilder_SessionSettings.InventorySizeMultiplier"/>
|
|
||||||
public float InventorySizeMultiplier
|
|
||||||
{
|
|
||||||
get => _settings.InventorySizeMultiplier; set { _settings.InventorySizeMultiplier = value; OnPropertyChanged(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc cref="MyObjectBuilder_SessionSettings.RefinerySpeedMultiplier"/>
|
|
||||||
public float RefinerySpeedMultiplier
|
|
||||||
{
|
|
||||||
get => _settings.RefinerySpeedMultiplier; set { _settings.RefinerySpeedMultiplier = value; OnPropertyChanged(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc cref="MyObjectBuilder_SessionSettings.AssemblerEfficiencyMultiplier"/>
|
|
||||||
public float AssemblerEfficiencyMultiplier
|
|
||||||
{
|
|
||||||
get => _settings.AssemblerEfficiencyMultiplier; set { _settings.AssemblerEfficiencyMultiplier = value; OnPropertyChanged(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc cref="MyObjectBuilder_SessionSettings.AssemblerSpeedMultiplier"/>
|
|
||||||
public float AssemblerSpeedMultiplier
|
|
||||||
{
|
|
||||||
get => _settings.AssemblerSpeedMultiplier; set { _settings.AssemblerSpeedMultiplier = value; OnPropertyChanged(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc cref="MyObjectBuilder_SessionSettings.GrinderSpeedMultiplier"/>
|
|
||||||
public float GrinderSpeedMultiplier
|
|
||||||
{
|
|
||||||
get => _settings.GrinderSpeedMultiplier; set { _settings.GrinderSpeedMultiplier = value; OnPropertyChanged(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc cref="MyObjectBuilder_SessionSettings.HackSpeedMultiplier"/>
|
|
||||||
public float HackSpeedMultiplier
|
|
||||||
{
|
|
||||||
get => _settings.HackSpeedMultiplier; set { _settings.HackSpeedMultiplier = value; OnPropertyChanged(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc cref="MyObjectBuilder_SessionSettings.WelderSpeedMultiplier"/>
|
|
||||||
public float WelderSpeedMultiplier
|
|
||||||
{
|
|
||||||
get => _settings.WelderSpeedMultiplier; set { _settings.WelderSpeedMultiplier = value; OnPropertyChanged(); }
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region NPCs
|
|
||||||
|
|
||||||
/// <inheritdoc cref="MyObjectBuilder_SessionSettings.EnableDrones"/>
|
|
||||||
public bool EnableDrones
|
|
||||||
{
|
|
||||||
get => _settings.EnableDrones; set { _settings.EnableDrones = value; OnPropertyChanged(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc cref="MyObjectBuilder_SessionSettings.EnableEncounters"/>
|
|
||||||
public bool EnableEncounters
|
|
||||||
{
|
|
||||||
get => _settings.EnableEncounters; set { _settings.EnableEncounters = value; OnPropertyChanged(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc cref="MyObjectBuilder_SessionSettings.EnableSpiders"/>
|
|
||||||
public bool EnableSpiders
|
|
||||||
{
|
|
||||||
get => _settings.EnableSpiders; set { _settings.EnableSpiders = value; OnPropertyChanged(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc cref="MyObjectBuilder_SessionSettings.EnableWolfs"/>
|
|
||||||
public bool EnableWolves
|
|
||||||
{
|
|
||||||
get => _settings.EnableWolfs; set { _settings.EnableWolfs = value; OnPropertyChanged(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc cref="MyObjectBuilder_SessionSettings.CargoShipsEnabled"/>
|
|
||||||
public bool EnableCargoShips
|
|
||||||
{
|
|
||||||
get => _settings.CargoShipsEnabled; set { _settings.CargoShipsEnabled = value; OnPropertyChanged(); }
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Environment
|
|
||||||
|
|
||||||
/// <inheritdoc cref="MyObjectBuilder_SessionSettings.EnableSunRotation"/>
|
|
||||||
public bool EnableSunRotation
|
|
||||||
{
|
|
||||||
get => _settings.EnableSunRotation; set { _settings.EnableSunRotation = value; OnPropertyChanged(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc cref="MyObjectBuilder_SessionSettings.EnableOxygenPressurization"/>
|
|
||||||
public bool EnableAirtightness
|
|
||||||
{
|
|
||||||
get => _settings.EnableOxygenPressurization; set { _settings.EnableOxygenPressurization = value; OnPropertyChanged(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc cref="MyObjectBuilder_SessionSettings.EnableOxygen"/>
|
|
||||||
public bool EnableOxygen
|
|
||||||
{
|
|
||||||
get => _settings.EnableOxygen; set { _settings.EnableOxygen = value; OnPropertyChanged(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc cref="MyObjectBuilder_SessionSettings.DestructibleBlocks"/>
|
|
||||||
public bool EnableDestructibleBlocks
|
|
||||||
{
|
|
||||||
get => _settings.DestructibleBlocks; set { _settings.DestructibleBlocks = value; OnPropertyChanged(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc cref="MyObjectBuilder_SessionSettings.EnableToolShake"/>
|
|
||||||
public bool EnableToolShake
|
|
||||||
{
|
|
||||||
get => _settings.EnableToolShake; set { _settings.EnableToolShake = value; OnPropertyChanged(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc cref="MyObjectBuilder_SessionSettings.EnableVoxelDestruction"/>
|
|
||||||
public bool EnableVoxelDestruction
|
|
||||||
{
|
|
||||||
get => _settings.EnableVoxelDestruction; set { _settings.EnableVoxelDestruction = value; OnPropertyChanged(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// List used to populate the environment hostility combo box.
|
|
||||||
/// </summary>
|
|
||||||
public List<string> EnvironmentHostilityValues { get; } = Enum.GetNames(typeof(MyEnvironmentHostilityEnum)).ToList();
|
|
||||||
|
|
||||||
/// <inheritdoc cref="MyObjectBuilder_SessionSettings.EnvironmentHostility"/>
|
|
||||||
public string EnvironmentHostility
|
|
||||||
{
|
|
||||||
get => _settings.EnvironmentHostility.ToString(); set { Enum.TryParse(value, true, out _settings.EnvironmentHostility); OnPropertyChanged(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc cref="MyObjectBuilder_SessionSettings.EnableFlora"/>
|
|
||||||
public bool EnableFlora
|
|
||||||
{
|
|
||||||
get => _settings.EnableFlora; set { _settings.EnableFlora = value; OnPropertyChanged(); }
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// List used to populate the game mode combobox.
|
|
||||||
/// </summary>
|
|
||||||
public List<string> GameModeValues { get; } = Enum.GetNames(typeof(MyGameModeEnum)).ToList();
|
|
||||||
|
|
||||||
/// <inheritdoc cref="MyObjectBuilder_SessionSettings.GameMode"/>
|
|
||||||
public string GameMode
|
|
||||||
{
|
|
||||||
get => _settings.GameMode.ToString(); set { Enum.TryParse(value, true, out _settings.GameMode); OnPropertyChanged(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc cref="MyObjectBuilder_SessionSettings.AutoHealing"/>
|
|
||||||
public bool EnableAutoHealing
|
|
||||||
{
|
|
||||||
get => _settings.AutoHealing; set { _settings.AutoHealing = value; OnPropertyChanged(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc cref="MyObjectBuilder_SessionSettings.EnableCopyPaste"/>
|
|
||||||
public bool EnableCopyPaste
|
|
||||||
{
|
|
||||||
get => _settings.EnableCopyPaste; set { _settings.EnableCopyPaste = value; OnPropertyChanged(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc cref="MyObjectBuilder_SessionSettings.ShowPlayerNamesOnHud"/>
|
|
||||||
public bool ShowPlayerNamesOnHud
|
|
||||||
{
|
|
||||||
get => _settings.ShowPlayerNamesOnHud; set { _settings.ShowPlayerNamesOnHud = value; OnPropertyChanged(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc cref="MyObjectBuilder_SessionSettings.Enable3rdPersonView"/>
|
|
||||||
public bool EnableThirdPerson
|
|
||||||
{
|
|
||||||
get => _settings.Enable3rdPersonView; set { _settings.Enable3rdPersonView = value; OnPropertyChanged(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc cref="MyObjectBuilder_SessionSettings.EnableSpectator"/>
|
|
||||||
public bool EnableSpectator
|
|
||||||
{
|
|
||||||
get => _settings.EnableSpectator; set { _settings.EnableSpectator = value; OnPropertyChanged(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc cref="MyObjectBuilder_SessionSettings.SpawnWithTools"/>
|
|
||||||
public bool SpawnWithTools
|
|
||||||
{
|
|
||||||
get => _settings.SpawnWithTools; set { _settings.SpawnWithTools = value; OnPropertyChanged(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc cref="MyObjectBuilder_SessionSettings.EnableConvertToStation"/>
|
|
||||||
public bool EnableConvertToStation
|
|
||||||
{
|
|
||||||
get => _settings.EnableConvertToStation; set { _settings.EnableConvertToStation = value; OnPropertyChanged(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc cref="MyObjectBuilder_SessionSettings.EnableJetpack"/>
|
|
||||||
public bool EnableJetpack
|
|
||||||
{
|
|
||||||
get => _settings.EnableJetpack; set { _settings.EnableJetpack = value; OnPropertyChanged(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc cref="MyObjectBuilder_SessionSettings.EnableRemoteBlockRemoval"/>
|
|
||||||
public bool EnableRemoteOwnerRemoval
|
|
||||||
{
|
|
||||||
get => _settings.EnableRemoteBlockRemoval; set { _settings.EnableRemoteBlockRemoval = value; OnPropertyChanged(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc cref="MyObjectBuilder_SessionSettings.EnableRespawnShips"/>
|
|
||||||
public bool EnableRespawnShips
|
|
||||||
{
|
|
||||||
get => _settings.EnableRespawnShips; set { _settings.EnableRespawnShips = value; OnPropertyChanged(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc cref="MyObjectBuilder_SessionSettings.EnableScripterRole"/>
|
|
||||||
public bool EnableScripterRole
|
|
||||||
{
|
|
||||||
get => _settings.EnableScripterRole; set { _settings.EnableScripterRole = value; OnPropertyChanged(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc cref="MyObjectBuilder_SessionSettings.RealisticSound"/>
|
|
||||||
public bool EnableRealisticSound
|
|
||||||
{
|
|
||||||
get => _settings.RealisticSound; set { _settings.RealisticSound = value; OnPropertyChanged(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc cref="MyObjectBuilder_SessionSettings.ResetOwnership"/>
|
|
||||||
public bool ResetOwnership
|
|
||||||
{
|
|
||||||
get => _settings.ResetOwnership; set { _settings.ResetOwnership = value; OnPropertyChanged(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc cref="MyObjectBuilder_SessionSettings.RespawnShipDelete"/>
|
|
||||||
public bool DeleteRespawnShips
|
|
||||||
{
|
|
||||||
get => _settings.RespawnShipDelete; set { _settings.RespawnShipDelete = value; OnPropertyChanged(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc cref="MyObjectBuilder_SessionSettings.ThrusterDamage"/>
|
|
||||||
public bool EnableThrusterDamage
|
|
||||||
{
|
|
||||||
get => _settings.ThrusterDamage; set { _settings.ThrusterDamage = value; OnPropertyChanged(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc cref="MyObjectBuilder_SessionSettings.WeaponsEnabled"/>
|
|
||||||
public bool EnableWeapons
|
|
||||||
{
|
|
||||||
get => _settings.WeaponsEnabled; set { _settings.WeaponsEnabled = value; OnPropertyChanged(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc cref="MyObjectBuilder_SessionSettings.EnableIngameScripts"/>
|
|
||||||
public bool EnableIngameScripts
|
|
||||||
{
|
|
||||||
get => _settings.EnableIngameScripts; set { _settings.EnableIngameScripts = value; OnPropertyChanged(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc cref="MyObjectBuilder_SessionSettings.AutoSaveInMinutes"/>
|
|
||||||
public uint AutosaveInterval
|
|
||||||
{
|
|
||||||
get => _settings.AutoSaveInMinutes; set { _settings.AutoSaveInMinutes = value; OnPropertyChanged(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc cref="MyObjectBuilder_SessionSettings.FloraDensity"/>
|
|
||||||
public int FloraDensity
|
|
||||||
{
|
|
||||||
get => _settings.FloraDensity; set { _settings.FloraDensity = value; OnPropertyChanged(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc cref="MyObjectBuilder_SessionSettings.FloraDensityMultiplier"/>
|
|
||||||
public float FloraDensityMultiplier
|
|
||||||
{
|
|
||||||
get => _settings.FloraDensityMultiplier; set { _settings.FloraDensityMultiplier = value; OnPropertyChanged(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc cref="MyObjectBuilder_SessionSettings.MaxBackupSaves"/>
|
|
||||||
public short MaxBackupSaves
|
|
||||||
{
|
|
||||||
get => _settings.MaxBackupSaves; set { _settings.MaxBackupSaves = value; OnPropertyChanged(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc cref="MyObjectBuilder_SessionSettings.MaxBlocksPerPlayer"/>
|
|
||||||
public int MaxBlocksPerPlayer
|
|
||||||
{
|
|
||||||
get => _settings.MaxBlocksPerPlayer; set { _settings.MaxBlocksPerPlayer = value; OnPropertyChanged(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc cref="MyObjectBuilder_SessionSettings.MaxFloatingObjects"/>
|
|
||||||
public short MaxFloatingObjects
|
|
||||||
{
|
|
||||||
get => _settings.MaxFloatingObjects; set { _settings.MaxFloatingObjects = value; OnPropertyChanged(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc cref="MyObjectBuilder_SessionSettings.MaxGridSize"/>
|
|
||||||
public int MaxGridSize
|
|
||||||
{
|
|
||||||
get => _settings.MaxGridSize; set { _settings.MaxGridSize = value; OnPropertyChanged(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc cref="MyObjectBuilder_SessionSettings.MaxPlayers"/>
|
|
||||||
public short MaxPlayers
|
|
||||||
{
|
|
||||||
get => _settings.MaxPlayers; set { _settings.MaxPlayers = value; OnPropertyChanged(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc cref="MyObjectBuilder_SessionSettings.PhysicsIterations"/>
|
|
||||||
public int PhysicsIterations
|
|
||||||
{
|
|
||||||
get => _settings.PhysicsIterations; set { _settings.PhysicsIterations = value; OnPropertyChanged(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc cref="MyObjectBuilder_SessionSettings.SpawnShipTimeMultiplier"/>
|
|
||||||
public float SpawnTimeMultiplier
|
|
||||||
{
|
|
||||||
get => _settings.SpawnShipTimeMultiplier; set { _settings.SpawnShipTimeMultiplier = value; OnPropertyChanged(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc cref="MyObjectBuilder_SessionSettings.SunRotationIntervalMinutes"/>
|
|
||||||
public float SunRotationInterval
|
|
||||||
{
|
|
||||||
get => _settings.SunRotationIntervalMinutes; set { _settings.SunRotationIntervalMinutes = value; OnPropertyChanged(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc cref="MyObjectBuilder_SessionSettings.ViewDistance"/>
|
|
||||||
public int ViewDistance
|
|
||||||
{
|
|
||||||
get => _settings.ViewDistance; set { _settings.ViewDistance = value; OnPropertyChanged(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc cref="MyObjectBuilder_SessionSettings.WorldSizeKm"/>
|
|
||||||
public int WorldSize
|
|
||||||
{
|
|
||||||
get => _settings.WorldSizeKm; set { _settings.WorldSizeKm = value; OnPropertyChanged(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc cref="MyObjectBuilder_SessionSettings.ProceduralDensity"/>
|
|
||||||
public float ProceduralDensity
|
|
||||||
{
|
|
||||||
get => _settings.ProceduralDensity; set { _settings.ProceduralDensity = value; OnPropertyChanged(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc cref="MyObjectBuilder_SessionSettings.ProceduralSeed"/>
|
|
||||||
public int ProceduralSeed
|
|
||||||
{
|
|
||||||
get => _settings.ProceduralSeed;
|
|
||||||
set { _settings.ProceduralSeed = value; OnPropertyChanged(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary />
|
|
||||||
public static implicit operator MyObjectBuilder_SessionSettings(SessionSettingsViewModel viewModel)
|
public static implicit operator MyObjectBuilder_SessionSettings(SessionSettingsViewModel viewModel)
|
||||||
{
|
{
|
||||||
viewModel._settings.BlockTypeLimits.Dictionary.Clear();
|
|
||||||
foreach (var limit in viewModel.BlockLimits)
|
|
||||||
viewModel._settings.BlockTypeLimits.Dictionary.Add(limit.BlockType, limit.Limit);
|
|
||||||
return viewModel._settings;
|
return viewModel._settings;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
253
Torch.Server/ViewModels/SessionSettingsViewModel1.cs
Normal file
253
Torch.Server/ViewModels/SessionSettingsViewModel1.cs
Normal file
@@ -0,0 +1,253 @@
|
|||||||
|
// This file is generated automatically! Any changes will be overwritten.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Torch;
|
||||||
|
using Torch.Collections;
|
||||||
|
using VRage.Game;
|
||||||
|
using VRage.Library.Utils;
|
||||||
|
using VRage.Serialization;
|
||||||
|
|
||||||
|
namespace Torch.Server.ViewModels
|
||||||
|
{
|
||||||
|
public class SessionSettingsViewModel : ViewModel
|
||||||
|
{
|
||||||
|
private MyObjectBuilder_SessionSettings _settings;
|
||||||
|
/// <inheritdoc cref="VRage.Game.MyObjectBuilder_SessionSettings.GameMode" />
|
||||||
|
public string GameMode { get => _settings.GameMode.ToString(); set { Enum.TryParse(value, true, out VRage.Library.Utils.MyGameModeEnum parsedVal); SetValue(ref _settings.GameMode, parsedVal); } }
|
||||||
|
public List<string> GameModeValues { get; } = new List<string> {"Creative", "Survival"};
|
||||||
|
|
||||||
|
/// <inheritdoc cref="VRage.Game.MyObjectBuilder_SessionSettings.InventorySizeMultiplier" />
|
||||||
|
public System.Single InventorySizeMultiplier { get => _settings.InventorySizeMultiplier; set => SetValue(ref _settings.InventorySizeMultiplier, value); }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="VRage.Game.MyObjectBuilder_SessionSettings.AssemblerSpeedMultiplier" />
|
||||||
|
public System.Single AssemblerSpeedMultiplier { get => _settings.AssemblerSpeedMultiplier; set => SetValue(ref _settings.AssemblerSpeedMultiplier, value); }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="VRage.Game.MyObjectBuilder_SessionSettings.AssemblerEfficiencyMultiplier" />
|
||||||
|
public System.Single AssemblerEfficiencyMultiplier { get => _settings.AssemblerEfficiencyMultiplier; set => SetValue(ref _settings.AssemblerEfficiencyMultiplier, value); }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="VRage.Game.MyObjectBuilder_SessionSettings.RefinerySpeedMultiplier" />
|
||||||
|
public System.Single RefinerySpeedMultiplier { get => _settings.RefinerySpeedMultiplier; set => SetValue(ref _settings.RefinerySpeedMultiplier, value); }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="VRage.Game.MyObjectBuilder_SessionSettings.OnlineMode" />
|
||||||
|
public string OnlineMode { get => _settings.OnlineMode.ToString(); set { Enum.TryParse(value, true, out VRage.Game.MyOnlineModeEnum parsedVal); SetValue(ref _settings.OnlineMode, parsedVal); } }
|
||||||
|
public List<string> OnlineModeValues { get; } = new List<string> {"OFFLINE", "PUBLIC", "FRIENDS", "PRIVATE"};
|
||||||
|
|
||||||
|
/// <inheritdoc cref="VRage.Game.MyObjectBuilder_SessionSettings.MaxPlayers" />
|
||||||
|
public System.Int16 MaxPlayers { get => _settings.MaxPlayers; set => SetValue(ref _settings.MaxPlayers, value); }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="VRage.Game.MyObjectBuilder_SessionSettings.MaxFloatingObjects" />
|
||||||
|
public System.Int16 MaxFloatingObjects { get => _settings.MaxFloatingObjects; set => SetValue(ref _settings.MaxFloatingObjects, value); }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="VRage.Game.MyObjectBuilder_SessionSettings.MaxBackupSaves" />
|
||||||
|
public System.Int16 MaxBackupSaves { get => _settings.MaxBackupSaves; set => SetValue(ref _settings.MaxBackupSaves, value); }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="VRage.Game.MyObjectBuilder_SessionSettings.MaxGridSize" />
|
||||||
|
public System.Int32 MaxGridSize { get => _settings.MaxGridSize; set => SetValue(ref _settings.MaxGridSize, value); }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="VRage.Game.MyObjectBuilder_SessionSettings.MaxBlocksPerPlayer" />
|
||||||
|
public System.Int32 MaxBlocksPerPlayer { get => _settings.MaxBlocksPerPlayer; set => SetValue(ref _settings.MaxBlocksPerPlayer, value); }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="VRage.Game.MyObjectBuilder_SessionSettings.EnableBlockLimits" />
|
||||||
|
public System.Boolean EnableBlockLimits { get => _settings.EnableBlockLimits; set => SetValue(ref _settings.EnableBlockLimits, value); }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="VRage.Game.MyObjectBuilder_SessionSettings.EnableRemoteBlockRemoval" />
|
||||||
|
public System.Boolean EnableRemoteBlockRemoval { get => _settings.EnableRemoteBlockRemoval; set => SetValue(ref _settings.EnableRemoteBlockRemoval, value); }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="VRage.Game.MyObjectBuilder_SessionSettings.EnvironmentHostility" />
|
||||||
|
public string EnvironmentHostility { get => _settings.EnvironmentHostility.ToString(); set { Enum.TryParse(value, true, out VRage.Game.MyEnvironmentHostilityEnum parsedVal); SetValue(ref _settings.EnvironmentHostility, parsedVal); } }
|
||||||
|
public List<string> EnvironmentHostilityValues { get; } = new List<string> {"SAFE", "NORMAL", "CATACLYSM", "CATACLYSM_UNREAL"};
|
||||||
|
|
||||||
|
/// <inheritdoc cref="VRage.Game.MyObjectBuilder_SessionSettings.AutoHealing" />
|
||||||
|
public System.Boolean AutoHealing { get => _settings.AutoHealing; set => SetValue(ref _settings.AutoHealing, value); }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="VRage.Game.MyObjectBuilder_SessionSettings.EnableCopyPaste" />
|
||||||
|
public System.Boolean EnableCopyPaste { get => _settings.EnableCopyPaste; set => SetValue(ref _settings.EnableCopyPaste, value); }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="VRage.Game.MyObjectBuilder_SessionSettings.WeaponsEnabled" />
|
||||||
|
public System.Boolean WeaponsEnabled { get => _settings.WeaponsEnabled; set => SetValue(ref _settings.WeaponsEnabled, value); }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="VRage.Game.MyObjectBuilder_SessionSettings.ShowPlayerNamesOnHud" />
|
||||||
|
public System.Boolean ShowPlayerNamesOnHud { get => _settings.ShowPlayerNamesOnHud; set => SetValue(ref _settings.ShowPlayerNamesOnHud, value); }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="VRage.Game.MyObjectBuilder_SessionSettings.ThrusterDamage" />
|
||||||
|
public System.Boolean ThrusterDamage { get => _settings.ThrusterDamage; set => SetValue(ref _settings.ThrusterDamage, value); }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="VRage.Game.MyObjectBuilder_SessionSettings.CargoShipsEnabled" />
|
||||||
|
public System.Boolean CargoShipsEnabled { get => _settings.CargoShipsEnabled; set => SetValue(ref _settings.CargoShipsEnabled, value); }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="VRage.Game.MyObjectBuilder_SessionSettings.EnableSpectator" />
|
||||||
|
public System.Boolean EnableSpectator { get => _settings.EnableSpectator; set => SetValue(ref _settings.EnableSpectator, value); }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="VRage.Game.MyObjectBuilder_SessionSettings.WorldSizeKm" />
|
||||||
|
public System.Int32 WorldSizeKm { get => _settings.WorldSizeKm; set => SetValue(ref _settings.WorldSizeKm, value); }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="VRage.Game.MyObjectBuilder_SessionSettings.RespawnShipDelete" />
|
||||||
|
public System.Boolean RespawnShipDelete { get => _settings.RespawnShipDelete; set => SetValue(ref _settings.RespawnShipDelete, value); }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="VRage.Game.MyObjectBuilder_SessionSettings.ResetOwnership" />
|
||||||
|
public System.Boolean ResetOwnership { get => _settings.ResetOwnership; set => SetValue(ref _settings.ResetOwnership, value); }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="VRage.Game.MyObjectBuilder_SessionSettings.WelderSpeedMultiplier" />
|
||||||
|
public System.Single WelderSpeedMultiplier { get => _settings.WelderSpeedMultiplier; set => SetValue(ref _settings.WelderSpeedMultiplier, value); }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="VRage.Game.MyObjectBuilder_SessionSettings.GrinderSpeedMultiplier" />
|
||||||
|
public System.Single GrinderSpeedMultiplier { get => _settings.GrinderSpeedMultiplier; set => SetValue(ref _settings.GrinderSpeedMultiplier, value); }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="VRage.Game.MyObjectBuilder_SessionSettings.RealisticSound" />
|
||||||
|
public System.Boolean RealisticSound { get => _settings.RealisticSound; set => SetValue(ref _settings.RealisticSound, value); }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="VRage.Game.MyObjectBuilder_SessionSettings.HackSpeedMultiplier" />
|
||||||
|
public System.Single HackSpeedMultiplier { get => _settings.HackSpeedMultiplier; set => SetValue(ref _settings.HackSpeedMultiplier, value); }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="VRage.Game.MyObjectBuilder_SessionSettings.PermanentDeath" />
|
||||||
|
public System.Nullable<System.Boolean> PermanentDeath { get => _settings.PermanentDeath; set => SetValue(ref _settings.PermanentDeath, value); }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="VRage.Game.MyObjectBuilder_SessionSettings.AutoSaveInMinutes" />
|
||||||
|
public System.UInt32 AutoSaveInMinutes { get => _settings.AutoSaveInMinutes; set => SetValue(ref _settings.AutoSaveInMinutes, value); }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="VRage.Game.MyObjectBuilder_SessionSettings.EnableSaving" />
|
||||||
|
public System.Boolean EnableSaving { get => _settings.EnableSaving; set => SetValue(ref _settings.EnableSaving, value); }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="VRage.Game.MyObjectBuilder_SessionSettings.EnableRespawnScreen" />
|
||||||
|
public System.Boolean EnableRespawnScreen { get => _settings.EnableRespawnScreen; set => SetValue(ref _settings.EnableRespawnScreen, value); }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="VRage.Game.MyObjectBuilder_SessionSettings.InfiniteAmmo" />
|
||||||
|
public System.Boolean InfiniteAmmo { get => _settings.InfiniteAmmo; set => SetValue(ref _settings.InfiniteAmmo, value); }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="VRage.Game.MyObjectBuilder_SessionSettings.EnableContainerDrops" />
|
||||||
|
public System.Boolean EnableContainerDrops { get => _settings.EnableContainerDrops; set => SetValue(ref _settings.EnableContainerDrops, value); }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="VRage.Game.MyObjectBuilder_SessionSettings.SpawnShipTimeMultiplier" />
|
||||||
|
public System.Single SpawnShipTimeMultiplier { get => _settings.SpawnShipTimeMultiplier; set => SetValue(ref _settings.SpawnShipTimeMultiplier, value); }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="VRage.Game.MyObjectBuilder_SessionSettings.ProceduralDensity" />
|
||||||
|
public System.Single ProceduralDensity { get => _settings.ProceduralDensity; set => SetValue(ref _settings.ProceduralDensity, value); }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="VRage.Game.MyObjectBuilder_SessionSettings.ProceduralSeed" />
|
||||||
|
public System.Int32 ProceduralSeed { get => _settings.ProceduralSeed; set => SetValue(ref _settings.ProceduralSeed, value); }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="VRage.Game.MyObjectBuilder_SessionSettings.DestructibleBlocks" />
|
||||||
|
public System.Boolean DestructibleBlocks { get => _settings.DestructibleBlocks; set => SetValue(ref _settings.DestructibleBlocks, value); }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="VRage.Game.MyObjectBuilder_SessionSettings.EnableIngameScripts" />
|
||||||
|
public System.Boolean EnableIngameScripts { get => _settings.EnableIngameScripts; set => SetValue(ref _settings.EnableIngameScripts, value); }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="VRage.Game.MyObjectBuilder_SessionSettings.ViewDistance" />
|
||||||
|
public System.Int32 ViewDistance { get => _settings.ViewDistance; set => SetValue(ref _settings.ViewDistance, value); }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="VRage.Game.MyObjectBuilder_SessionSettings.FloraDensity" />
|
||||||
|
public System.Int32 FloraDensity { get => _settings.FloraDensity; set => SetValue(ref _settings.FloraDensity, value); }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="VRage.Game.MyObjectBuilder_SessionSettings.EnableToolShake" />
|
||||||
|
public System.Boolean EnableToolShake { get => _settings.EnableToolShake; set => SetValue(ref _settings.EnableToolShake, value); }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="VRage.Game.MyObjectBuilder_SessionSettings.VoxelGeneratorVersion" />
|
||||||
|
public System.Int32 VoxelGeneratorVersion { get => _settings.VoxelGeneratorVersion; set => SetValue(ref _settings.VoxelGeneratorVersion, value); }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="VRage.Game.MyObjectBuilder_SessionSettings.EnableOxygen" />
|
||||||
|
public System.Boolean EnableOxygen { get => _settings.EnableOxygen; set => SetValue(ref _settings.EnableOxygen, value); }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="VRage.Game.MyObjectBuilder_SessionSettings.EnableOxygenPressurization" />
|
||||||
|
public System.Boolean EnableOxygenPressurization { get => _settings.EnableOxygenPressurization; set => SetValue(ref _settings.EnableOxygenPressurization, value); }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="VRage.Game.MyObjectBuilder_SessionSettings.Enable3rdPersonView" />
|
||||||
|
public System.Boolean Enable3rdPersonView { get => _settings.Enable3rdPersonView; set => SetValue(ref _settings.Enable3rdPersonView, value); }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="VRage.Game.MyObjectBuilder_SessionSettings.EnableEncounters" />
|
||||||
|
public System.Boolean EnableEncounters { get => _settings.EnableEncounters; set => SetValue(ref _settings.EnableEncounters, value); }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="VRage.Game.MyObjectBuilder_SessionSettings.EnableFlora" />
|
||||||
|
public System.Boolean EnableFlora { get => _settings.EnableFlora; set => SetValue(ref _settings.EnableFlora, value); }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="VRage.Game.MyObjectBuilder_SessionSettings.EnableConvertToStation" />
|
||||||
|
public System.Boolean EnableConvertToStation { get => _settings.EnableConvertToStation; set => SetValue(ref _settings.EnableConvertToStation, value); }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="VRage.Game.MyObjectBuilder_SessionSettings.StationVoxelSupport" />
|
||||||
|
public System.Boolean StationVoxelSupport { get => _settings.StationVoxelSupport; set => SetValue(ref _settings.StationVoxelSupport, value); }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="VRage.Game.MyObjectBuilder_SessionSettings.EnableSunRotation" />
|
||||||
|
public System.Boolean EnableSunRotation { get => _settings.EnableSunRotation; set => SetValue(ref _settings.EnableSunRotation, value); }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="VRage.Game.MyObjectBuilder_SessionSettings.EnableRespawnShips" />
|
||||||
|
public System.Boolean EnableRespawnShips { get => _settings.EnableRespawnShips; set => SetValue(ref _settings.EnableRespawnShips, value); }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="VRage.Game.MyObjectBuilder_SessionSettings.ScenarioEditMode" />
|
||||||
|
public System.Boolean ScenarioEditMode { get => _settings.ScenarioEditMode; set => SetValue(ref _settings.ScenarioEditMode, value); }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="VRage.Game.MyObjectBuilder_SessionSettings.Scenario" />
|
||||||
|
public System.Boolean Scenario { get => _settings.Scenario; set => SetValue(ref _settings.Scenario, value); }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="VRage.Game.MyObjectBuilder_SessionSettings.CanJoinRunning" />
|
||||||
|
public System.Boolean CanJoinRunning { get => _settings.CanJoinRunning; set => SetValue(ref _settings.CanJoinRunning, value); }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="VRage.Game.MyObjectBuilder_SessionSettings.PhysicsIterations" />
|
||||||
|
public System.Int32 PhysicsIterations { get => _settings.PhysicsIterations; set => SetValue(ref _settings.PhysicsIterations, value); }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="VRage.Game.MyObjectBuilder_SessionSettings.SunRotationIntervalMinutes" />
|
||||||
|
public System.Single SunRotationIntervalMinutes { get => _settings.SunRotationIntervalMinutes; set => SetValue(ref _settings.SunRotationIntervalMinutes, value); }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="VRage.Game.MyObjectBuilder_SessionSettings.EnableJetpack" />
|
||||||
|
public System.Boolean EnableJetpack { get => _settings.EnableJetpack; set => SetValue(ref _settings.EnableJetpack, value); }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="VRage.Game.MyObjectBuilder_SessionSettings.SpawnWithTools" />
|
||||||
|
public System.Boolean SpawnWithTools { get => _settings.SpawnWithTools; set => SetValue(ref _settings.SpawnWithTools, value); }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="VRage.Game.MyObjectBuilder_SessionSettings.StartInRespawnScreen" />
|
||||||
|
public System.Boolean StartInRespawnScreen { get => _settings.StartInRespawnScreen; set => SetValue(ref _settings.StartInRespawnScreen, value); }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="VRage.Game.MyObjectBuilder_SessionSettings.EnableVoxelDestruction" />
|
||||||
|
public System.Boolean EnableVoxelDestruction { get => _settings.EnableVoxelDestruction; set => SetValue(ref _settings.EnableVoxelDestruction, value); }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="VRage.Game.MyObjectBuilder_SessionSettings.MaxDrones" />
|
||||||
|
public System.Int32 MaxDrones { get => _settings.MaxDrones; set => SetValue(ref _settings.MaxDrones, value); }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="VRage.Game.MyObjectBuilder_SessionSettings.EnableDrones" />
|
||||||
|
public System.Boolean EnableDrones { get => _settings.EnableDrones; set => SetValue(ref _settings.EnableDrones, value); }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="VRage.Game.MyObjectBuilder_SessionSettings.EnableWolfs" />
|
||||||
|
public System.Boolean EnableWolfs { get => _settings.EnableWolfs; set => SetValue(ref _settings.EnableWolfs, value); }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="VRage.Game.MyObjectBuilder_SessionSettings.EnableSpiders" />
|
||||||
|
public System.Boolean EnableSpiders { get => _settings.EnableSpiders; set => SetValue(ref _settings.EnableSpiders, value); }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="VRage.Game.MyObjectBuilder_SessionSettings.FloraDensityMultiplier" />
|
||||||
|
public System.Single FloraDensityMultiplier { get => _settings.FloraDensityMultiplier; set => SetValue(ref _settings.FloraDensityMultiplier, value); }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="VRage.Game.MyObjectBuilder_SessionSettings.EnableStructuralSimulation" />
|
||||||
|
public System.Boolean EnableStructuralSimulation { get => _settings.EnableStructuralSimulation; set => SetValue(ref _settings.EnableStructuralSimulation, value); }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="VRage.Game.MyObjectBuilder_SessionSettings.MaxActiveFracturePieces" />
|
||||||
|
public System.Int32 MaxActiveFracturePieces { get => _settings.MaxActiveFracturePieces; set => SetValue(ref _settings.MaxActiveFracturePieces, value); }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="VRage.Game.MyObjectBuilder_SessionSettings.BlockTypeLimits" />
|
||||||
|
public VRage.Serialization.SerializableDictionary<System.String, System.Int16> BlockTypeLimits { get => _settings.BlockTypeLimits; set => SetValue(ref _settings.BlockTypeLimits, value); }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="VRage.Game.MyObjectBuilder_SessionSettings.EnableScripterRole" />
|
||||||
|
public System.Boolean EnableScripterRole { get => _settings.EnableScripterRole; set => SetValue(ref _settings.EnableScripterRole, value); }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="VRage.Game.MyObjectBuilder_SessionSettings.MinDropContainerRespawnTime" />
|
||||||
|
public System.Int32 MinDropContainerRespawnTime { get => _settings.MinDropContainerRespawnTime; set => SetValue(ref _settings.MinDropContainerRespawnTime, value); }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="VRage.Game.MyObjectBuilder_SessionSettings.MaxDropContainerRespawnTime" />
|
||||||
|
public System.Int32 MaxDropContainerRespawnTime { get => _settings.MaxDropContainerRespawnTime; set => SetValue(ref _settings.MaxDropContainerRespawnTime, value); }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="VRage.Game.MyObjectBuilder_SessionSettings.EnableTurretsFriendlyFire" />
|
||||||
|
public System.Boolean EnableTurretsFriendlyFire { get => _settings.EnableTurretsFriendlyFire; set => SetValue(ref _settings.EnableTurretsFriendlyFire, value); }
|
||||||
|
|
||||||
|
/// <inheritdoc cref="VRage.Game.MyObjectBuilder_SessionSettings.EnableSubgridDamage" />
|
||||||
|
public System.Boolean EnableSubgridDamage { get => _settings.EnableSubgridDamage; set => SetValue(ref _settings.EnableSubgridDamage, value); }
|
||||||
|
|
||||||
|
|
||||||
|
public SessionSettingsViewModel(MyObjectBuilder_SessionSettings settings)
|
||||||
|
{
|
||||||
|
_settings = settings;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static implicit operator MyObjectBuilder_SessionSettings(SessionSettingsViewModel viewModel)
|
||||||
|
{
|
||||||
|
return viewModel._settings;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -3,7 +3,7 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using SteamSDK;
|
using Steamworks;
|
||||||
|
|
||||||
namespace Torch.Server.ViewModels
|
namespace Torch.Server.ViewModels
|
||||||
{
|
{
|
||||||
@@ -15,7 +15,7 @@ namespace Torch.Server.ViewModels
|
|||||||
public SteamUserViewModel(ulong id)
|
public SteamUserViewModel(ulong id)
|
||||||
{
|
{
|
||||||
SteamId = id;
|
SteamId = id;
|
||||||
Name = SteamAPI.Instance.Friends.GetPersonaName(id);
|
Name = SteamFriends.GetFriendPersonaName(new CSteamID(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
public SteamUserViewModel() : this(0) { }
|
public SteamUserViewModel() : this(0) { }
|
||||||
|
@@ -3,12 +3,11 @@
|
|||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:local="clr-namespace:Torch.Server"
|
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
Title="Add Workshop Item" Height="200" Width="400">
|
Title="Add Workshop Item" Height="200" Width="400">
|
||||||
<DockPanel Background="LightGray">
|
<DockPanel>
|
||||||
<Label DockPanel.Dock="Top" Content="Add each workshop URL or ID on its own line." HorizontalAlignment="Center"/>
|
<Label DockPanel.Dock="Top" Content="Add each workshop URL or ID on its own line." HorizontalAlignment="Center"/>
|
||||||
<Button DockPanel.Dock="Bottom" Content="Done" Margin="5,0,5,5" Click="Done_Clicked"/>
|
<Button DockPanel.Dock="Bottom" Content="Done" Margin="5,0,5,5" Click="Done_Clicked"/>
|
||||||
<TextBox x:Name="urlBlock" Margin="5,0,5,5" Background="White" AcceptsReturn="True"/>
|
<TextBox x:Name="urlBlock" Margin="5,0,5,5" AcceptsReturn="True"/>
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
</Window>
|
</Window>
|
||||||
|
@@ -3,7 +3,6 @@
|
|||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:local="clr-namespace:Torch.Server"
|
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d">
|
||||||
<Grid>
|
<Grid>
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
@@ -11,7 +10,7 @@
|
|||||||
<RowDefinition Height="Auto"/>
|
<RowDefinition Height="Auto"/>
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<ScrollViewer x:Name="ChatScroller" Grid.Row="0" Margin="5,5,5,5" HorizontalScrollBarVisibility="Disabled">
|
<ScrollViewer x:Name="ChatScroller" Grid.Row="0" Margin="5,5,5,5" HorizontalScrollBarVisibility="Disabled">
|
||||||
<TextBlock x:Name="ChatItems" />
|
<TextBlock x:Name="ChatItems" TextWrapping="Wrap" />
|
||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
<Grid Grid.Row="1">
|
<Grid Grid.Row="1">
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
|
@@ -4,6 +4,7 @@ using System.Collections.Specialized;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
@@ -15,11 +16,11 @@ using System.Windows.Media.Imaging;
|
|||||||
using System.Windows.Navigation;
|
using System.Windows.Navigation;
|
||||||
using System.Windows.Shapes;
|
using System.Windows.Shapes;
|
||||||
using System.Windows.Threading;
|
using System.Windows.Threading;
|
||||||
|
using NLog;
|
||||||
using Torch;
|
using Torch;
|
||||||
using Sandbox;
|
using Sandbox;
|
||||||
using Sandbox.Engine.Multiplayer;
|
using Sandbox.Engine.Multiplayer;
|
||||||
using Sandbox.Game.World;
|
using Sandbox.Game.World;
|
||||||
using SteamSDK;
|
|
||||||
using Torch.API;
|
using Torch.API;
|
||||||
using Torch.API.Managers;
|
using Torch.API.Managers;
|
||||||
using Torch.API.Session;
|
using Torch.API.Session;
|
||||||
@@ -34,22 +35,48 @@ namespace Torch.Server
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public partial class ChatControl : UserControl
|
public partial class ChatControl : UserControl
|
||||||
{
|
{
|
||||||
private TorchBase _server;
|
private static Logger _log = LogManager.GetCurrentClassLogger();
|
||||||
|
private ITorchServer _server;
|
||||||
|
|
||||||
public ChatControl()
|
public ChatControl()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
this.IsVisibleChanged += OnIsVisibleChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnIsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
|
||||||
|
{
|
||||||
|
_log.Info($"VisibleChanged: {IsVisible}");
|
||||||
|
if (IsVisible)
|
||||||
|
{
|
||||||
|
Task.Run(() =>
|
||||||
|
{
|
||||||
|
Thread.Sleep(100);
|
||||||
|
|
||||||
|
Dispatcher.Invoke(() =>
|
||||||
|
{
|
||||||
|
Message.Focus();
|
||||||
|
Keyboard.Focus(Message);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void BindServer(ITorchServer server)
|
public void BindServer(ITorchServer server)
|
||||||
{
|
{
|
||||||
_server = (TorchBase)server;
|
_server = server;
|
||||||
|
|
||||||
|
server.Initialized += Server_Initialized ;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Server_Initialized(ITorchServer obj)
|
||||||
|
{
|
||||||
Dispatcher.InvokeAsync(() =>
|
Dispatcher.InvokeAsync(() =>
|
||||||
{
|
{
|
||||||
ChatItems.Inlines.Clear();
|
ChatItems.Inlines.Clear();
|
||||||
});
|
});
|
||||||
|
|
||||||
var sessionManager = server.Managers.GetManager<ITorchSessionManager>();
|
var sessionManager = _server.Managers.GetManager<ITorchSessionManager>();
|
||||||
if (sessionManager != null)
|
if (sessionManager != null)
|
||||||
sessionManager.SessionStateChanged += SessionStateChanged;
|
sessionManager.SessionStateChanged += SessionStateChanged;
|
||||||
}
|
}
|
||||||
@@ -139,9 +166,7 @@ namespace Torch.Server
|
|||||||
InsertMessage(new TorchChatMessage("Server", text, MyFontEnum.DarkBlue));
|
InsertMessage(new TorchChatMessage("Server", text, MyFontEnum.DarkBlue));
|
||||||
_server.Invoke(() =>
|
_server.Invoke(() =>
|
||||||
{
|
{
|
||||||
string response = commands.HandleCommandFromServer(text);
|
commands.HandleCommandFromServer(text);
|
||||||
if (!string.IsNullOrWhiteSpace(response))
|
|
||||||
InsertMessage(new TorchChatMessage("Server", response, MyFontEnum.Blue));
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@@ -3,244 +3,149 @@
|
|||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:local="clr-namespace:Torch.Server.Views"
|
|
||||||
xmlns:viewModels="clr-namespace:Torch.Server.ViewModels"
|
xmlns:viewModels="clr-namespace:Torch.Server.ViewModels"
|
||||||
mc:Ignorable="d"
|
xmlns:managers="clr-namespace:Torch.Server.Managers"
|
||||||
Background="White">
|
xmlns:system="clr-namespace:System;assembly=mscorlib"
|
||||||
|
xmlns:validationRules="clr-namespace:Torch.Server.Views.ValidationRules"
|
||||||
|
xmlns:views="clr-namespace:Torch.Views;assembly=Torch"
|
||||||
|
mc:Ignorable="d">
|
||||||
|
<UserControl.Resources>
|
||||||
|
<ResourceDictionary>
|
||||||
|
<ResourceDictionary.MergedDictionaries>
|
||||||
|
<ResourceDictionary Source="Resources.xaml" />
|
||||||
|
</ResourceDictionary.MergedDictionaries>
|
||||||
|
</ResourceDictionary>
|
||||||
|
</UserControl.Resources>
|
||||||
<UserControl.DataContext>
|
<UserControl.DataContext>
|
||||||
<viewModels:ConfigDedicatedViewModel />
|
<viewModels:ConfigDedicatedViewModel />
|
||||||
</UserControl.DataContext>
|
</UserControl.DataContext>
|
||||||
<Grid>
|
<Grid>
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="Auto"/>
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition/>
|
<RowDefinition />
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<DockPanel Grid.Row="0">
|
<DockPanel Grid.Row="0">
|
||||||
<Label Content="World:" DockPanel.Dock="Left" />
|
<Label Content="World:" DockPanel.Dock="Left" />
|
||||||
<Button Content="New World" Margin="3" DockPanel.Dock="Right" Click="NewWorld_OnClick"/>
|
<Button Content="Import World Config" Margin="3" Padding="3" DockPanel.Dock="Right" Click="ImportConfig_OnClick" ToolTip="Override the DS config with the one from the selected world." IsEnabled="{Binding ElementName=WorldList, Path=Items.Count, Mode=OneWay}"/>
|
||||||
<ComboBox Text="{Binding LoadWorld}" ItemsSource="{Binding WorldPaths}" IsEditable="True" Margin="3" SelectionChanged="Selector_OnSelectionChanged"/>
|
<Button Content="New World" Margin="3" Padding="3" DockPanel.Dock="Right" Click="NewWorld_OnClick"/>
|
||||||
|
<ComboBox x:Name="WorldList" ItemsSource="{Binding Worlds}" SelectedItem="{Binding SelectedWorld}" Margin="3"
|
||||||
|
SelectionChanged="Selector_OnSelectionChanged">
|
||||||
|
<ComboBox.ItemTemplate>
|
||||||
|
<DataTemplate DataType="managers:WorldViewModel">
|
||||||
|
<StackPanel>
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<Label Content="{Binding Checkpoint.SessionName}" FontWeight="Bold" Padding="0" />
|
||||||
|
<Label Content="{Binding WorldPath}" Padding="5,0,0,0" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<Label Content="Size (KB): " Padding="0" />
|
||||||
|
<Label Content="{Binding WorldSizeKB}" Padding="0" />
|
||||||
|
<Label Content="Last saved: " Padding="5,0,0,0" />
|
||||||
|
<Label Content="{Binding Checkpoint.LastSaveTime}" Padding="0" />
|
||||||
|
</StackPanel>
|
||||||
|
</StackPanel>
|
||||||
|
</DataTemplate>
|
||||||
|
</ComboBox.ItemTemplate>
|
||||||
|
</ComboBox>
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
<Grid Grid.Row="1">
|
<Grid Grid.Row="1">
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="Auto"/>
|
<ColumnDefinition Width="7*" />
|
||||||
<ColumnDefinition/>
|
<ColumnDefinition Width="10*" />
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
<Grid Grid.Column="0">
|
<Grid Grid.Column="0">
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition/>
|
<RowDefinition />
|
||||||
<RowDefinition Height="Auto"/>
|
<RowDefinition Height="Auto" />
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<ScrollViewer Grid.Row="0" Margin="3">
|
<ScrollViewer VerticalScrollBarVisibility="Auto">
|
||||||
<StackPanel Orientation="Horizontal">
|
<Grid>
|
||||||
<StackPanel Margin="3" DockPanel.Dock="Left">
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
<ColumnDefinition />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<StackPanel Grid.Column="0" Margin="3" DockPanel.Dock="Left">
|
||||||
<Label Content="Server Name" />
|
<Label Content="Server Name" />
|
||||||
<TextBox Text="{Binding ServerName}" Margin="3,0,3,3" Width="160" />
|
<TextBox Text="{Binding ServerName}" Margin="3,0,3,3" Width="160" />
|
||||||
<Label Content="World Name" />
|
<Label Content="World Name" />
|
||||||
<TextBox Text="{Binding WorldName}" Margin="3,0,3,3" Width="160" />
|
<TextBox Text="{Binding WorldName}" Margin="3,0,3,3" Width="160" />
|
||||||
<Label Content="Whitelist Group ID" />
|
<Label Content="Server Description" />
|
||||||
<TextBox Text="{Binding GroupId}" Margin="3,0,3,3" Width="160" />
|
<TextBox Text="{Binding ServerDescription}" Margin="3,0,3,3" Width="160" Height="100"
|
||||||
|
AcceptsReturn="true" VerticalScrollBarVisibility="Auto"/>
|
||||||
|
<Label Content="Whitelist Group ID" />
|
||||||
|
<TextBox Margin="3,0,3,3" Width="160" Style="{StaticResource ValidatedTextBox}">
|
||||||
|
<TextBox.Text>
|
||||||
|
<Binding Path="GroupId" UpdateSourceTrigger="PropertyChanged"
|
||||||
|
ValidatesOnDataErrors="True" NotifyOnValidationError="True">
|
||||||
|
<Binding.ValidationRules>
|
||||||
|
<validationRules:NumberValidationRule />
|
||||||
|
</Binding.ValidationRules>
|
||||||
|
</Binding>
|
||||||
|
</TextBox.Text>
|
||||||
|
</TextBox>
|
||||||
<Label Content="Server IP" />
|
<Label Content="Server IP" />
|
||||||
<StackPanel Orientation="Horizontal" Margin="3,0,3,3">
|
<StackPanel Orientation="Horizontal" Margin="3,0,3,3">
|
||||||
<TextBox Text="{Binding IP}" Width="100" Height="20" />
|
<TextBox Text="{Binding IP}" Width="100" Height="20" />
|
||||||
<Label Content=":" Width="12" />
|
<Label Content=":" Width="12" />
|
||||||
<TextBox Text="{Binding Port}" Width="48" Height="20" />
|
<TextBox Text="{Binding Port}" Width="48" Height="20" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
<Label Content="Server Password"/>
|
||||||
|
<TextBox Text="{Binding Password}" Width="160"/>
|
||||||
<CheckBox IsChecked="{Binding PauseGameWhenEmpty}" Content="Pause When Empty" Margin="3" />
|
<CheckBox IsChecked="{Binding PauseGameWhenEmpty}" Content="Pause When Empty" Margin="3" />
|
||||||
|
<CheckBox IsChecked="{Binding AutodetectDependencies}" Content="Auto Detect Dependencies" Margin="3" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<StackPanel Margin="3">
|
<StackPanel Grid.Column="1" Margin="3">
|
||||||
<Label Content="Mods" />
|
<Label Content="Mods" />
|
||||||
<TextBox Text="{Binding Mods}" Margin="3" Height="100" AcceptsReturn="true" VerticalScrollBarVisibility="Auto"/>
|
<TextBox Margin="3" Height="60" AcceptsReturn="true" VerticalScrollBarVisibility="Auto"
|
||||||
|
Style="{StaticResource ValidatedTextBox}">
|
||||||
|
<TextBox.Text>
|
||||||
|
<Binding Path="Mods" UpdateSourceTrigger="PropertyChanged"
|
||||||
|
ValidatesOnDataErrors="True" NotifyOnValidationError="True"
|
||||||
|
Converter="{StaticResource ListConverterUInt64}">
|
||||||
|
<Binding.ValidationRules>
|
||||||
|
<validationRules:ListConverterValidationRule Type="system:UInt64" />
|
||||||
|
</Binding.ValidationRules>
|
||||||
|
</Binding>
|
||||||
|
</TextBox.Text>
|
||||||
|
</TextBox>
|
||||||
<Label Content="Administrators" />
|
<Label Content="Administrators" />
|
||||||
<TextBox Text="{Binding Administrators}" Margin="3" Height="100" AcceptsReturn="true" VerticalScrollBarVisibility="Auto"/>
|
<TextBox Text="{Binding Administrators, Converter={StaticResource ListConverterString}}"
|
||||||
|
Margin="3"
|
||||||
|
Height="100" AcceptsReturn="true" VerticalScrollBarVisibility="Auto" />
|
||||||
|
<Label Content="Reserved Players" />
|
||||||
|
<TextBox Margin="3" Height="100" AcceptsReturn="true" VerticalScrollBarVisibility="Auto"
|
||||||
|
Style="{StaticResource ValidatedTextBox}">
|
||||||
|
<TextBox.Text>
|
||||||
|
<Binding Path="Reserved" UpdateSourceTrigger="PropertyChanged"
|
||||||
|
ValidatesOnDataErrors="True" NotifyOnValidationError="True"
|
||||||
|
Converter="{StaticResource ListConverterUInt64}">
|
||||||
|
<Binding.ValidationRules>
|
||||||
|
<validationRules:ListConverterValidationRule Type="system:UInt64" />
|
||||||
|
</Binding.ValidationRules>
|
||||||
|
</Binding>
|
||||||
|
</TextBox.Text>
|
||||||
|
</TextBox>
|
||||||
<Label Content="Banned Players" />
|
<Label Content="Banned Players" />
|
||||||
<TextBox Text="{Binding Banned}" Margin="3" Height="100" AcceptsReturn="true" VerticalScrollBarVisibility="Auto"/>
|
<TextBox Margin="3" Height="100" AcceptsReturn="true" VerticalScrollBarVisibility="Auto"
|
||||||
|
Style="{StaticResource ValidatedTextBox}">
|
||||||
|
<TextBox.Text>
|
||||||
|
<Binding Path="Banned" UpdateSourceTrigger="PropertyChanged"
|
||||||
|
ValidatesOnDataErrors="True" NotifyOnValidationError="True"
|
||||||
|
Converter="{StaticResource ListConverterUInt64}">
|
||||||
|
<Binding.ValidationRules>
|
||||||
|
<validationRules:ListConverterValidationRule Type="system:UInt64" />
|
||||||
|
</Binding.ValidationRules>
|
||||||
|
</Binding>
|
||||||
|
</TextBox.Text>
|
||||||
|
</TextBox>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</StackPanel>
|
</Grid>
|
||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
<Button Grid.Row="1" Content="Save Config" Margin="3" Click="Save_OnClick" />
|
<Button Grid.Row="1" Content="Save Config" Margin="3" Click="Save_OnClick" />
|
||||||
</Grid>
|
</Grid>
|
||||||
<ScrollViewer Grid.Column="1" Margin="3">
|
<views:PropertyGrid Grid.Column="1" Margin="3" DataContext="{Binding SessionSettings}" IgnoreDisplay ="True" />
|
||||||
<StackPanel DataContext="{Binding SessionSettings}">
|
<GridSplitter Grid.Column="1" HorizontalAlignment="Left" VerticalAlignment="Stretch" ShowsPreview="True"
|
||||||
<Expander Header="Block Limits">
|
Width="2" />
|
||||||
<StackPanel Margin="10,0,0,0">
|
|
||||||
<StackPanel Orientation="Horizontal">
|
|
||||||
<TextBox Text="{Binding MaxBlocksPerPlayer}" Margin="3" Width="70" />
|
|
||||||
<Label Content="Max Blocks Per Player" />
|
|
||||||
</StackPanel>
|
|
||||||
<StackPanel Orientation="Horizontal">
|
|
||||||
<TextBox Text="{Binding MaxGridSize}" Margin="3" Width="70" />
|
|
||||||
<Label Content="Max Grid Size" />
|
|
||||||
</StackPanel>
|
|
||||||
<Button Content="Add" Margin="3" Click="AddLimit_OnClick" />
|
|
||||||
<ListView ItemsSource="{Binding BlockLimits}" Margin="3">
|
|
||||||
<ListView.ItemTemplate>
|
|
||||||
<DataTemplate>
|
|
||||||
<StackPanel Orientation="Horizontal">
|
|
||||||
<TextBox Text="{Binding BlockType}" Width="150" Margin="3" />
|
|
||||||
<TextBox Text="{Binding Limit}" Width="50" Margin="3" />
|
|
||||||
<Button Content=" X " Margin="3" Click="RemoveLimit_OnClick" />
|
|
||||||
</StackPanel>
|
|
||||||
</DataTemplate>
|
|
||||||
</ListView.ItemTemplate>
|
|
||||||
</ListView>
|
|
||||||
</StackPanel>
|
|
||||||
</Expander>
|
|
||||||
<Expander Header="Multipliers">
|
|
||||||
<StackPanel Margin="10,0,0,0">
|
|
||||||
<StackPanel Orientation="Horizontal">
|
|
||||||
<TextBox Text="{Binding InventorySizeMultiplier}" Margin="3" Width="70" />
|
|
||||||
<Label Content="Inventory Size" />
|
|
||||||
</StackPanel>
|
|
||||||
<StackPanel Orientation="Horizontal">
|
|
||||||
<TextBox Text="{Binding RefinerySpeedMultiplier}" Margin="3" Width="70" />
|
|
||||||
<Label Content="Refinery Speed" />
|
|
||||||
</StackPanel>
|
|
||||||
<StackPanel Orientation="Horizontal">
|
|
||||||
<TextBox Text="{Binding AssemblerEfficiencyMultiplier}" Margin="3" Width="70" />
|
|
||||||
<Label Content="Assembler Efficiency" />
|
|
||||||
</StackPanel>
|
|
||||||
<StackPanel Orientation="Horizontal">
|
|
||||||
<TextBox Text="{Binding AssemblerSpeedMultiplier}" Margin="3" Width="70" />
|
|
||||||
<Label Content="Assembler Speed" />
|
|
||||||
</StackPanel>
|
|
||||||
<StackPanel Orientation="Horizontal">
|
|
||||||
<TextBox Text="{Binding WelderSpeedMultiplier}" Margin="3" Width="70" />
|
|
||||||
<Label Content="Welder Speed" />
|
|
||||||
</StackPanel>
|
|
||||||
<StackPanel Orientation="Horizontal">
|
|
||||||
<TextBox Text="{Binding GrinderSpeedMultiplier}" Margin="3" Width="70" />
|
|
||||||
<Label Content="Grinder Speed" />
|
|
||||||
</StackPanel>
|
|
||||||
<StackPanel Orientation="Horizontal">
|
|
||||||
<TextBox Text="{Binding HackSpeedMultiplier}" Margin="3" Width="70" />
|
|
||||||
<Label Content="Hacking Speed" />
|
|
||||||
</StackPanel>
|
|
||||||
</StackPanel>
|
|
||||||
</Expander>
|
|
||||||
<Expander Header="NPCs">
|
|
||||||
<StackPanel Margin="10,0,0,0">
|
|
||||||
<CheckBox IsChecked="{Binding EnableDrones}" Content="Enable Drones" Margin="3" />
|
|
||||||
<CheckBox IsChecked="{Binding EnableEncounters}" Content="Enable Encounters" Margin="3" />
|
|
||||||
<CheckBox IsChecked="{Binding EnableSpiders}" Content="Enable Spiders" Margin="3" />
|
|
||||||
<CheckBox IsChecked="{Binding EnableWolves}" Content="Enable Wolves" Margin="3" />
|
|
||||||
<CheckBox IsChecked="{Binding EnableCargoShips}" Content="Enable Cargo Ships" Margin="3" />
|
|
||||||
</StackPanel>
|
|
||||||
</Expander>
|
|
||||||
<Expander Header="Environment">
|
|
||||||
<StackPanel Margin="10,0,0,0">
|
|
||||||
<StackPanel Orientation="Horizontal" ToolTip="Increases physics precision at the cost of performance.">
|
|
||||||
<TextBox Text="{Binding PhysicsIterations}" Margin="3" Width="70" />
|
|
||||||
<Label Content="Physics Iterations" />
|
|
||||||
</StackPanel>
|
|
||||||
<StackPanel Orientation="Horizontal">
|
|
||||||
<TextBox Text="{Binding MaxFloatingObjects}" Margin="3" Width="70" />
|
|
||||||
<Label Content="Max Floating Objects" />
|
|
||||||
</StackPanel>
|
|
||||||
<CheckBox IsChecked="{Binding EnableRealisticSound}" Content="Enable Realistic Sound"
|
|
||||||
Margin="3" />
|
|
||||||
<CheckBox IsChecked="{Binding EnableAirtightness}" Content="Enable Airtightness" Margin="3" />
|
|
||||||
<CheckBox IsChecked="{Binding EnableOxygen}" Content="Enable Oxygen" Margin="3" />
|
|
||||||
<CheckBox IsChecked="{Binding EnableDestructibleBlocks}"
|
|
||||||
Content="Enable Destructible Blocks" Margin="3" />
|
|
||||||
<CheckBox IsChecked="{Binding EnableToolShake}" Content="Enable Tool Shake" Margin="3" />
|
|
||||||
<CheckBox IsChecked="{Binding EnableVoxelDestruction}" Content="Enable Voxel Destruction"
|
|
||||||
Margin="3" />
|
|
||||||
<CheckBox IsChecked="{Binding EnableSunRotation}" Content="Enable Sun Rotation" Margin="3" />
|
|
||||||
<StackPanel Orientation="Horizontal">
|
|
||||||
<TextBox Text="{Binding SunRotationInterval}" Margin="3" Width="70" />
|
|
||||||
<Label Content="Sun Rotation Interval (mins)" />
|
|
||||||
</StackPanel>
|
|
||||||
<CheckBox IsChecked="{Binding EnableFlora}" Content="Enable Flora" Margin="3" />
|
|
||||||
<StackPanel Orientation="Horizontal">
|
|
||||||
<TextBox Text="{Binding FloraDensity}" Margin="3" Width="70" />
|
|
||||||
<Label Content="Flora Density" />
|
|
||||||
</StackPanel>
|
|
||||||
<StackPanel Orientation="Horizontal">
|
|
||||||
<TextBox Text="{Binding FloraDensityMultiplier}" Margin="3" Width="70" />
|
|
||||||
<Label Content="Flora Density Multiplier" />
|
|
||||||
</StackPanel>
|
|
||||||
<StackPanel Orientation="Horizontal">
|
|
||||||
<TextBox Text="{Binding ViewDistance}" Margin="3" Width="70" />
|
|
||||||
<Label Content="View Distance (meters)" />
|
|
||||||
</StackPanel>
|
|
||||||
<StackPanel Orientation="Horizontal">
|
|
||||||
<TextBox Text="{Binding WorldSize}" Margin="3" Width="70" />
|
|
||||||
<Label Content="World Size (km)" />
|
|
||||||
</StackPanel>
|
|
||||||
<StackPanel Orientation="Horizontal">
|
|
||||||
<ComboBox SelectedItem="{Binding EnvironmentHostility}"
|
|
||||||
ItemsSource="{Binding EnvironmentHostilityValues}" Margin="3" Width="100"
|
|
||||||
DockPanel.Dock="Left" />
|
|
||||||
<Label Content="Environment Hostility" />
|
|
||||||
</StackPanel>
|
|
||||||
<StackPanel Orientation="Horizontal">
|
|
||||||
<TextBox Text="{Binding ProceduralDensity}" Margin="3" Width="70" />
|
|
||||||
<Label Content="Procedural Density" />
|
|
||||||
</StackPanel>
|
|
||||||
<StackPanel Orientation="Horizontal">
|
|
||||||
<TextBox Text="{Binding ProceduralSeed}" Margin="3" Width="70" />
|
|
||||||
<Label Content="Procedural Seed" />
|
|
||||||
</StackPanel>
|
|
||||||
</StackPanel>
|
|
||||||
</Expander>
|
|
||||||
<Expander Header="Players">
|
|
||||||
<StackPanel Margin="10,0,0,0">
|
|
||||||
<StackPanel Orientation="Horizontal">
|
|
||||||
<TextBox Text="{Binding MaxPlayers}" Margin="3" Width="70" />
|
|
||||||
<Label Content="Max Players" />
|
|
||||||
</StackPanel>
|
|
||||||
<CheckBox IsChecked="{Binding EnableThirdPerson}" Content="Enable 3rd Person Camera"
|
|
||||||
Margin="3" />
|
|
||||||
<CheckBox IsChecked="{Binding EnableJetpack}" Content="Enable Jetpack" Margin="3" />
|
|
||||||
<CheckBox IsChecked="{Binding EnableAutoHealing}" Content="Auto Healing" Margin="3" />
|
|
||||||
<CheckBox IsChecked="{Binding EnableCopyPaste}" Content="Enable Copy/Paste" Margin="3" />
|
|
||||||
<CheckBox IsChecked="{Binding ShowPlayerNamesOnHud}" Content="Show Player Names on HUD"
|
|
||||||
Margin="3" />
|
|
||||||
<StackPanel Orientation="Horizontal">
|
|
||||||
<TextBox Text="{Binding SpawnTimeMultiplier}" Margin="3" Width="70" />
|
|
||||||
<Label Content="Respawn Time Multiplier" />
|
|
||||||
</StackPanel>
|
|
||||||
<CheckBox IsChecked="{Binding ResetOwnership}" Content="Reset Ownership" Margin="3" />
|
|
||||||
<CheckBox IsChecked="{Binding SpawnWithTools}" Content="Spawn With Tools" Margin="3" />
|
|
||||||
</StackPanel>
|
|
||||||
</Expander>
|
|
||||||
<Expander Header="Miscellaneous">
|
|
||||||
<StackPanel Margin="10,0,0,0">
|
|
||||||
<StackPanel Orientation="Horizontal">
|
|
||||||
<TextBox Text="{Binding AutosaveInterval}" Margin="3" Width="70" />
|
|
||||||
<Label Content="Autosave Interval (minutes)" />
|
|
||||||
</StackPanel>
|
|
||||||
<CheckBox IsChecked="{Binding EnableConvertToStation}" Content="Enable Convert to Station"
|
|
||||||
Margin="3" />
|
|
||||||
|
|
||||||
<CheckBox IsChecked="{Binding EnableRemoteOwnerRemoval}"
|
|
||||||
Content="Enable Remote Ownership Removal" Margin="3" />
|
|
||||||
<CheckBox IsChecked="{Binding EnableRespawnShips}" Content="Enable Respawn Ships"
|
|
||||||
Margin="3" />
|
|
||||||
<CheckBox IsChecked="{Binding EnableScripterRole}" Content="Enable Scripter Role"
|
|
||||||
Margin="3" />
|
|
||||||
<CheckBox IsChecked="{Binding EnableSpectator}" Content="Enable Spectator Camera"
|
|
||||||
Margin="3" />
|
|
||||||
<CheckBox IsChecked="{Binding DeleteRespawnShips}" Content="Remove Respawn Ships on Logoff"
|
|
||||||
Margin="3" />
|
|
||||||
<CheckBox IsChecked="{Binding EnableThrusterDamage}" Content="Enable Thruster Damage"
|
|
||||||
Margin="3" />
|
|
||||||
<CheckBox IsChecked="{Binding EnableWeapons}" Content="Enable Weapons" Margin="3" />
|
|
||||||
<CheckBox IsChecked="{Binding EnableIngameScripts}" Content="Enable Ingame Scripts"
|
|
||||||
Margin="3" />
|
|
||||||
<StackPanel Orientation="Horizontal">
|
|
||||||
<ComboBox SelectedItem="{Binding GameMode}" ItemsSource="{Binding GameModeValues}"
|
|
||||||
Margin="3" Width="100" DockPanel.Dock="Left" />
|
|
||||||
<Label Content="Game Mode" />
|
|
||||||
</StackPanel>
|
|
||||||
<StackPanel Orientation="Horizontal">
|
|
||||||
<TextBox Text="{Binding MaxBackupSaves}" Margin="3" Width="70" />
|
|
||||||
<Label Content="Max Backup Saves" />
|
|
||||||
</StackPanel>
|
|
||||||
</StackPanel>
|
|
||||||
</Expander>
|
|
||||||
</StackPanel>
|
|
||||||
</ScrollViewer>
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
</UserControl>
|
</UserControl>
|
@@ -1,6 +1,15 @@
|
|||||||
using System.Windows;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Windows;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
|
using System.Windows.Data;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using System.Windows.Threading;
|
||||||
using Torch.API.Managers;
|
using Torch.API.Managers;
|
||||||
|
using Torch.Server.Annotations;
|
||||||
using Torch.Server.Managers;
|
using Torch.Server.Managers;
|
||||||
using Torch.Server.ViewModels;
|
using Torch.Server.ViewModels;
|
||||||
|
|
||||||
@@ -9,15 +18,74 @@ namespace Torch.Server.Views
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Interaction logic for ConfigControl.xaml
|
/// Interaction logic for ConfigControl.xaml
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public partial class ConfigControl : UserControl
|
public partial class ConfigControl : UserControl, INotifyPropertyChanged
|
||||||
{
|
{
|
||||||
private InstanceManager _instanceManager;
|
private InstanceManager _instanceManager;
|
||||||
|
|
||||||
|
private bool _configValid;
|
||||||
|
public bool ConfigValid { get => _configValid; private set { _configValid = value; OnPropertyChanged(); } }
|
||||||
|
|
||||||
|
private List<BindingExpression> _bindingExpressions = new List<BindingExpression>();
|
||||||
|
|
||||||
public ConfigControl()
|
public ConfigControl()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
_instanceManager = TorchBase.Instance.Managers.GetManager<InstanceManager>();
|
_instanceManager = TorchBase.Instance.Managers.GetManager<InstanceManager>();
|
||||||
|
_instanceManager.InstanceLoaded += _instanceManager_InstanceLoaded;
|
||||||
DataContext = _instanceManager.DedicatedConfig;
|
DataContext = _instanceManager.DedicatedConfig;
|
||||||
|
|
||||||
|
// Gets called once all children are loaded
|
||||||
|
Dispatcher.BeginInvoke(DispatcherPriority.Loaded, new Action(ApplyStyles));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CheckValid()
|
||||||
|
{
|
||||||
|
ConfigValid = !_bindingExpressions.Any(x => x.HasError);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ApplyStyles()
|
||||||
|
{
|
||||||
|
foreach (var textbox in GetAllChildren<TextBox>(this))
|
||||||
|
{
|
||||||
|
textbox.Style = (Style)Resources["ValidatedTextBox"];
|
||||||
|
var binding = textbox.GetBindingExpression(TextBox.TextProperty);
|
||||||
|
if (binding == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
_bindingExpressions.Add(binding);
|
||||||
|
textbox.TextChanged += (sender, args) =>
|
||||||
|
{
|
||||||
|
binding.UpdateSource();
|
||||||
|
CheckValid();
|
||||||
|
};
|
||||||
|
|
||||||
|
textbox.LostKeyboardFocus += (sender, args) =>
|
||||||
|
{
|
||||||
|
if (binding.HasError)
|
||||||
|
binding.UpdateTarget();
|
||||||
|
CheckValid();
|
||||||
|
};
|
||||||
|
|
||||||
|
CheckValid();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEnumerable<T> GetAllChildren<T>(DependencyObject control) where T : DependencyObject
|
||||||
|
{
|
||||||
|
var children = LogicalTreeHelper.GetChildren(control).OfType<DependencyObject>();
|
||||||
|
foreach (var child in children)
|
||||||
|
{
|
||||||
|
if (child is T t)
|
||||||
|
yield return t;
|
||||||
|
|
||||||
|
foreach (var grandChild in GetAllChildren<T>(child))
|
||||||
|
yield return grandChild;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void _instanceManager_InstanceLoaded(ConfigDedicatedViewModel obj)
|
||||||
|
{
|
||||||
|
Dispatcher.Invoke(() => DataContext = obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Save_OnClick(object sender, RoutedEventArgs e)
|
private void Save_OnClick(object sender, RoutedEventArgs e)
|
||||||
@@ -25,20 +93,9 @@ namespace Torch.Server.Views
|
|||||||
_instanceManager.SaveConfig();
|
_instanceManager.SaveConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RemoveLimit_OnClick(object sender, RoutedEventArgs e)
|
private void ImportConfig_OnClick(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
var vm = (BlockLimitViewModel)((Button)sender).DataContext;
|
_instanceManager.ImportSelectedWorldConfig();
|
||||||
_instanceManager.DedicatedConfig.SessionSettings.BlockLimits.Remove(vm);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void AddLimit_OnClick(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
_instanceManager.DedicatedConfig.SessionSettings.BlockLimits.Add(new BlockLimitViewModel(_instanceManager.DedicatedConfig.SessionSettings, "", 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void NewWorld_OnClick(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
MessageBox.Show("Feature coming soon :)");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Selector_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
|
private void Selector_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||||
@@ -46,8 +103,24 @@ namespace Torch.Server.Views
|
|||||||
//The control doesn't update the binding before firing the event.
|
//The control doesn't update the binding before firing the event.
|
||||||
if (e.AddedItems.Count > 0)
|
if (e.AddedItems.Count > 0)
|
||||||
{
|
{
|
||||||
_instanceManager.SelectWorld((string)e.AddedItems[0]);
|
var result = MessageBoxResult.Yes; //MessageBox.Show("Do you want to import the session settings from the selected world?", "Import Config", MessageBoxButton.YesNo);
|
||||||
|
var world = (WorldViewModel)e.AddedItems[0];
|
||||||
|
_instanceManager.SelectWorld(world.WorldPath, result != MessageBoxResult.Yes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public event PropertyChangedEventHandler PropertyChanged;
|
||||||
|
|
||||||
|
[NotifyPropertyChangedInvocator]
|
||||||
|
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
|
||||||
|
{
|
||||||
|
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void NewWorld_OnClick(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
var c = new WorldGeneratorDialog(_instanceManager);
|
||||||
|
c.Show();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
29
Torch.Server/Views/Converters/BooleanAndConverter.cs
Normal file
29
Torch.Server/Views/Converters/BooleanAndConverter.cs
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows.Data;
|
||||||
|
|
||||||
|
namespace Torch.Server.Views.Converters
|
||||||
|
{
|
||||||
|
public class BooleanAndConverter : IMultiValueConverter
|
||||||
|
{
|
||||||
|
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
foreach (var value in values)
|
||||||
|
{
|
||||||
|
if (value is bool b && b == false)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
throw new NotSupportedException("BooleanAndConverter is a OneWay converter.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
40
Torch.Server/Views/Converters/DefinitionToIdConverter.cs
Normal file
40
Torch.Server/Views/Converters/DefinitionToIdConverter.cs
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
using System;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Data;
|
||||||
|
using Sandbox.Definitions;
|
||||||
|
using VRage.Game;
|
||||||
|
|
||||||
|
namespace Torch.Server.Views.Converters
|
||||||
|
{
|
||||||
|
public class DefinitionToIdConverter : IValueConverter
|
||||||
|
{
|
||||||
|
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
// ReSharper disable once PossibleNullReferenceException
|
||||||
|
MyDefinitionId id = ((MyDefinitionBase) value).Id;
|
||||||
|
string typeName = id.TypeId.ToString();
|
||||||
|
if (typeName.StartsWith("MyObjectBuilder_"))
|
||||||
|
typeName = typeName.Substring("MyObjectBuilder_".Length);
|
||||||
|
string subtype = id.SubtypeName;
|
||||||
|
return string.IsNullOrWhiteSpace(subtype) ? typeName : $"{typeName}: {subtype}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
// ReSharper disable once PossibleNullReferenceException
|
||||||
|
string[] parts = value.ToString().Split(':');
|
||||||
|
Type type;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
type = Type.GetType(parts[0]);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
type = Type.GetType("MyObjectBuilder_" + parts[0]);
|
||||||
|
}
|
||||||
|
return MyDefinitionManager.Static.GetDefinition(
|
||||||
|
new MyDefinitionId(type, parts.Length > 1 ? parts[1].Trim() : ""));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -1,8 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Windows.Data;
|
using System.Windows.Data;
|
||||||
|
|
||||||
namespace Torch.Server.Views.Converters
|
namespace Torch.Server.Views.Converters
|
||||||
@@ -15,9 +11,6 @@ namespace Torch.Server.Views.Converters
|
|||||||
public object Convert(object value, Type targetType, object parameter,
|
public object Convert(object value, Type targetType, object parameter,
|
||||||
System.Globalization.CultureInfo culture)
|
System.Globalization.CultureInfo culture)
|
||||||
{
|
{
|
||||||
if (targetType != typeof(bool))
|
|
||||||
throw new InvalidOperationException("The target must be a boolean");
|
|
||||||
|
|
||||||
return !(bool)value;
|
return !(bool)value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
54
Torch.Server/Views/Converters/ListConverter.cs
Normal file
54
Torch.Server/Views/Converters/ListConverter.cs
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows.Data;
|
||||||
|
using System.Windows.Navigation;
|
||||||
|
|
||||||
|
namespace Torch.Server.Views.Converters
|
||||||
|
{
|
||||||
|
public class ListConverter : IValueConverter
|
||||||
|
{
|
||||||
|
public Type Type { get; set; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
if (!(value is IList list))
|
||||||
|
throw new InvalidOperationException("Value is not the proper type.");
|
||||||
|
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
foreach (var item in list)
|
||||||
|
{
|
||||||
|
sb.AppendLine(item.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
var list = (IList)Activator.CreateInstance(typeof(List<>).MakeGenericType(Type));
|
||||||
|
var converter = TypeDescriptor.GetConverter(Type);
|
||||||
|
var input = ((string)value).Split(new[] {Environment.NewLine}, StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
foreach (var item in input)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
list.Add(converter.ConvertFromString(item));
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("Could not convert input value.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -14,8 +14,8 @@
|
|||||||
<Grid Margin="3">
|
<Grid Margin="3">
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="Auto"/>
|
<RowDefinition Height="Auto"/>
|
||||||
<RowDefinition Height="*" />
|
|
||||||
<RowDefinition/>
|
<RowDefinition/>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<StackPanel Grid.Row="0">
|
<StackPanel Grid.Row="0">
|
||||||
<Label Content="{Binding FullName}" FontSize="16" />
|
<Label Content="{Binding FullName}" FontSize="16" />
|
||||||
@@ -25,7 +25,7 @@
|
|||||||
</StackPanel>
|
</StackPanel>
|
||||||
<Label Content="Properties"/>
|
<Label Content="Properties"/>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<Expander Grid.Row="1" Header="Block Properties">
|
<Expander Grid.Row="1" Header="Block Properties" IsExpanded="true">
|
||||||
<ListView ItemsSource="{Binding Properties}" Margin="3" IsEnabled="True">
|
<ListView ItemsSource="{Binding Properties}" Margin="3" IsEnabled="True">
|
||||||
<ListView.ItemTemplate>
|
<ListView.ItemTemplate>
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
|
@@ -28,6 +28,15 @@ namespace Torch.Server.Views.Blocks
|
|||||||
public BlockView()
|
public BlockView()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
|
ThemeControl.UpdateDynamicControls += UpdateResourceDict;
|
||||||
|
UpdateResourceDict(ThemeControl.currentTheme);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateResourceDict(ResourceDictionary dictionary)
|
||||||
|
{
|
||||||
|
this.Resources.MergedDictionaries.Clear();
|
||||||
|
this.Resources.MergedDictionaries.Add(dictionary);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@@ -3,8 +3,6 @@
|
|||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:local="clr-namespace:Torch.Server.Views.Blocks"
|
|
||||||
xmlns:blocks="clr-namespace:Torch.Server.ViewModels.Blocks"
|
|
||||||
xmlns:converters="clr-namespace:Torch.Server.Views.Converters"
|
xmlns:converters="clr-namespace:Torch.Server.Views.Converters"
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d">
|
||||||
<UserControl.Resources>
|
<UserControl.Resources>
|
||||||
|
@@ -26,6 +26,15 @@ namespace Torch.Server.Views.Blocks
|
|||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
DataContextChanged += OnDataContextChanged;
|
DataContextChanged += OnDataContextChanged;
|
||||||
|
|
||||||
|
ThemeControl.UpdateDynamicControls += UpdateResourceDict;
|
||||||
|
UpdateResourceDict(ThemeControl.currentTheme);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateResourceDict(ResourceDictionary dictionary)
|
||||||
|
{
|
||||||
|
this.Resources.MergedDictionaries.Clear();
|
||||||
|
this.Resources.MergedDictionaries.Add(dictionary);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnDataContextChanged(object sender, DependencyPropertyChangedEventArgs args)
|
private void OnDataContextChanged(object sender, DependencyPropertyChangedEventArgs args)
|
||||||
|
30
Torch.Server/Views/Entities/CharacterView.xaml
Normal file
30
Torch.Server/Views/Entities/CharacterView.xaml
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
<UserControl x:Class="Torch.Server.Views.Entities.CharacterView"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:entities="clr-namespace:Torch.Server.ViewModels.Entities"
|
||||||
|
xmlns:local="clr-namespace:Torch.Server.Views.Entities"
|
||||||
|
mc:Ignorable="d">
|
||||||
|
<UserControl.DataContext>
|
||||||
|
<entities:CharacterViewModel />
|
||||||
|
</UserControl.DataContext>
|
||||||
|
<Grid>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
<RowDefinition Height="*"/>
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<StackPanel Grid.Row="0" Orientation="Horizontal">
|
||||||
|
<Label Content="Name" Width="100"/>
|
||||||
|
<TextBox Text="{Binding Name}" Margin="3"/>
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Grid.Row="1" Orientation="Horizontal">
|
||||||
|
<Label Content="Position" Width="100"/>
|
||||||
|
<TextBox Text="{Binding Position}" Margin="3" />
|
||||||
|
</StackPanel>
|
||||||
|
<ScrollViewer Grid.Row="2" Margin="3" VerticalScrollBarVisibility="Auto">
|
||||||
|
<local:EntityControlsView DataContext="{Binding}"/>
|
||||||
|
</ScrollViewer>
|
||||||
|
</Grid>
|
||||||
|
</UserControl>
|
37
Torch.Server/Views/Entities/CharacterView.xaml.cs
Normal file
37
Torch.Server/Views/Entities/CharacterView.xaml.cs
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
using System.Windows.Data;
|
||||||
|
using System.Windows.Documents;
|
||||||
|
using System.Windows.Input;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using System.Windows.Media.Imaging;
|
||||||
|
using System.Windows.Navigation;
|
||||||
|
using System.Windows.Shapes;
|
||||||
|
|
||||||
|
namespace Torch.Server.Views.Entities
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interaction logic for GridView.xaml
|
||||||
|
/// </summary>
|
||||||
|
public partial class CharacterView : UserControl
|
||||||
|
{
|
||||||
|
public CharacterView()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
|
||||||
|
ThemeControl.UpdateDynamicControls += UpdateResourceDict;
|
||||||
|
UpdateResourceDict(ThemeControl.currentTheme);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateResourceDict(ResourceDictionary dictionary)
|
||||||
|
{
|
||||||
|
this.Resources.MergedDictionaries.Clear();
|
||||||
|
this.Resources.MergedDictionaries.Add(dictionary);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -17,6 +17,15 @@ namespace Torch.Server.Views.Entities
|
|||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
DataContextChanged += OnDataContextChanged;
|
DataContextChanged += OnDataContextChanged;
|
||||||
|
|
||||||
|
ThemeControl.UpdateDynamicControls += UpdateResourceDict;
|
||||||
|
UpdateResourceDict(ThemeControl.currentTheme);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateResourceDict(ResourceDictionary dictionary)
|
||||||
|
{
|
||||||
|
this.Resources.MergedDictionaries.Clear();
|
||||||
|
this.Resources.MergedDictionaries.Add(dictionary);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnDataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
|
private void OnDataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
using System.Windows.Controls;
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
|
||||||
namespace Torch.Server.Views.Entities
|
namespace Torch.Server.Views.Entities
|
||||||
{
|
{
|
||||||
@@ -10,6 +11,15 @@ namespace Torch.Server.Views.Entities
|
|||||||
public EntityControlsView()
|
public EntityControlsView()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
|
ThemeControl.UpdateDynamicControls += UpdateResourceDict;
|
||||||
|
UpdateResourceDict(ThemeControl.currentTheme);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateResourceDict(ResourceDictionary dictionary)
|
||||||
|
{
|
||||||
|
this.Resources.MergedDictionaries.Clear();
|
||||||
|
this.Resources.MergedDictionaries.Add(dictionary);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
<UserControl x:Class="Torch.Server.Views.Entities.GridView"
|
<UserControl x:Class="Torch.Server.Views.Entities.GridView"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
@@ -6,11 +6,13 @@
|
|||||||
xmlns:entities="clr-namespace:Torch.Server.ViewModels.Entities"
|
xmlns:entities="clr-namespace:Torch.Server.ViewModels.Entities"
|
||||||
xmlns:local="clr-namespace:Torch.Server.Views.Entities"
|
xmlns:local="clr-namespace:Torch.Server.Views.Entities"
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d">
|
||||||
|
|
||||||
<UserControl.DataContext>
|
<UserControl.DataContext>
|
||||||
<entities:GridViewModel />
|
<entities:GridViewModel />
|
||||||
</UserControl.DataContext>
|
</UserControl.DataContext>
|
||||||
<Grid>
|
<Grid>
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
<RowDefinition Height="Auto"/>
|
<RowDefinition Height="Auto"/>
|
||||||
<RowDefinition Height="Auto"/>
|
<RowDefinition Height="Auto"/>
|
||||||
<RowDefinition Height="*"/>
|
<RowDefinition Height="*"/>
|
||||||
@@ -23,7 +25,11 @@
|
|||||||
<Label Content="Position" Width="100"/>
|
<Label Content="Position" Width="100"/>
|
||||||
<TextBox Text="{Binding Position}" Margin="3" />
|
<TextBox Text="{Binding Position}" Margin="3" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<ScrollViewer Grid.Row="2" Margin="3" VerticalScrollBarVisibility="Auto">
|
<StackPanel Grid.Row="2" Orientation="Horizontal">
|
||||||
|
<Label Content="EntityID" Width="100"/>
|
||||||
|
<TextBox Text="{Binding Id, Mode=OneWay}" Margin="3" />
|
||||||
|
</StackPanel>
|
||||||
|
<ScrollViewer Grid.Row="3" Margin="3" VerticalScrollBarVisibility="Auto">
|
||||||
<local:EntityControlsView DataContext="{Binding}"/>
|
<local:EntityControlsView DataContext="{Binding}"/>
|
||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
@@ -23,6 +23,15 @@ namespace Torch.Server.Views.Entities
|
|||||||
public GridView()
|
public GridView()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
|
ThemeControl.UpdateDynamicControls += UpdateResourceDict;
|
||||||
|
UpdateResourceDict(ThemeControl.currentTheme);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateResourceDict(ResourceDictionary dictionary)
|
||||||
|
{
|
||||||
|
this.Resources.MergedDictionaries.Clear();
|
||||||
|
this.Resources.MergedDictionaries.Add(dictionary);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -25,6 +25,15 @@ namespace Torch.Server.Views.Entities
|
|||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
DataContextChanged += VoxelMapView_DataContextChanged;
|
DataContextChanged += VoxelMapView_DataContextChanged;
|
||||||
|
|
||||||
|
ThemeControl.UpdateDynamicControls += UpdateResourceDict;
|
||||||
|
UpdateResourceDict(ThemeControl.currentTheme);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateResourceDict(ResourceDictionary dictionary)
|
||||||
|
{
|
||||||
|
this.Resources.MergedDictionaries.Clear();
|
||||||
|
this.Resources.MergedDictionaries.Add(dictionary);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void VoxelMapView_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
|
private void VoxelMapView_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
|
||||||
|
@@ -3,39 +3,58 @@
|
|||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:local="clr-namespace:Torch.Server.Views"
|
|
||||||
xmlns:viewModels="clr-namespace:Torch.Server.ViewModels"
|
|
||||||
xmlns:entities="clr-namespace:Torch.Server.ViewModels.Entities"
|
xmlns:entities="clr-namespace:Torch.Server.ViewModels.Entities"
|
||||||
xmlns:blocks="clr-namespace:Torch.Server.ViewModels.Blocks"
|
xmlns:blocks="clr-namespace:Torch.Server.ViewModels.Blocks"
|
||||||
|
xmlns:converters="clr-namespace:Torch.Server.Views.Converters"
|
||||||
|
xmlns:viewModels="clr-namespace:Torch.Server.ViewModels"
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d">
|
||||||
|
<UserControl.DataContext>
|
||||||
|
<viewModels:EntityTreeViewModel />
|
||||||
|
</UserControl.DataContext>
|
||||||
|
<UserControl.Resources>
|
||||||
|
<converters:DefinitionToIdConverter x:Key="DefinitionConverter" />
|
||||||
|
</UserControl.Resources>
|
||||||
<Grid>
|
<Grid>
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition/>
|
<ColumnDefinition Width="5*"/>
|
||||||
<ColumnDefinition MinWidth="300" Width="Auto"/>
|
<ColumnDefinition Width="5*" />
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
<Grid Grid.Column="0">
|
<Grid Grid.Column="0">
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition/>
|
<RowDefinition />
|
||||||
<RowDefinition Height="Auto"/>
|
<RowDefinition Height="Auto" />
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<TreeView Grid.Row="0" Margin="3" DockPanel.Dock="Top" SelectedItemChanged="TreeView_OnSelectedItemChanged" TreeViewItem.Expanded="TreeViewItem_OnExpanded">
|
<TreeView Grid.Row="0" Margin="3" DockPanel.Dock="Top" SelectedItemChanged="TreeView_OnSelectedItemChanged"
|
||||||
|
TreeViewItem.Expanded="TreeViewItem_OnExpanded">
|
||||||
<TreeView.Resources>
|
<TreeView.Resources>
|
||||||
<HierarchicalDataTemplate DataType="{x:Type entities:GridViewModel}" ItemsSource="{Binding Blocks}">
|
<HierarchicalDataTemplate DataType="{x:Type entities:GridViewModel}"
|
||||||
|
ItemsSource="{Binding Path=Blocks}">
|
||||||
<TextBlock Text="{Binding DescriptiveName}" />
|
<TextBlock Text="{Binding DescriptiveName}" />
|
||||||
|
<HierarchicalDataTemplate.ItemTemplate>
|
||||||
|
<HierarchicalDataTemplate ItemsSource="{Binding Value.Values}">
|
||||||
|
<TextBlock>
|
||||||
|
<Run Text="{Binding Path=Key, Converter={StaticResource DefinitionConverter}, Mode=OneWay}" />
|
||||||
|
<Run Text="{Binding Path=Value.Count, StringFormat=' ({0} blocks)', Mode=OneWay}" />
|
||||||
|
</TextBlock>
|
||||||
|
<HierarchicalDataTemplate.ItemTemplate>
|
||||||
|
<DataTemplate DataType="{x:Type blocks:BlockViewModel}">
|
||||||
|
<TextBlock Text="{Binding Path=Name}" />
|
||||||
|
</DataTemplate>
|
||||||
|
</HierarchicalDataTemplate.ItemTemplate>
|
||||||
|
</HierarchicalDataTemplate>
|
||||||
|
</HierarchicalDataTemplate.ItemTemplate>
|
||||||
</HierarchicalDataTemplate>
|
</HierarchicalDataTemplate>
|
||||||
<DataTemplate DataType="{x:Type blocks:BlockViewModel}">
|
<HierarchicalDataTemplate DataType="{x:Type entities:VoxelMapViewModel}"
|
||||||
<TextBlock Text="{Binding Path=Name}" />
|
ItemsSource="{Binding AttachedGrids}">
|
||||||
</DataTemplate>
|
<TextBlock Text="{Binding Name}" />
|
||||||
<HierarchicalDataTemplate DataType="{x:Type entities:VoxelMapViewModel}" ItemsSource="{Binding AttachedGrids}">
|
|
||||||
<TextBlock Text="{Binding Name}"/>
|
|
||||||
</HierarchicalDataTemplate>
|
</HierarchicalDataTemplate>
|
||||||
</TreeView.Resources>
|
</TreeView.Resources>
|
||||||
<TreeViewItem ItemsSource="{Binding Grids}">
|
<TreeViewItem ItemsSource="{Binding Path=Grids.Values}">
|
||||||
<TreeViewItem.Header>
|
<TreeViewItem.Header>
|
||||||
<TextBlock Text="{Binding Grids.Count, StringFormat=Grids ({0})}" />
|
<TextBlock Text="{Binding Grids.Count, StringFormat=Grids ({0})}" />
|
||||||
</TreeViewItem.Header>
|
</TreeViewItem.Header>
|
||||||
</TreeViewItem>
|
</TreeViewItem>
|
||||||
<TreeViewItem ItemsSource="{Binding Characters}">
|
<TreeViewItem ItemsSource="{Binding Characters.Values}">
|
||||||
<TreeViewItem.Header>
|
<TreeViewItem.Header>
|
||||||
<TextBlock Text="{Binding Characters.Count, StringFormat=Characters ({0})}" />
|
<TextBlock Text="{Binding Characters.Count, StringFormat=Characters ({0})}" />
|
||||||
</TreeViewItem.Header>
|
</TreeViewItem.Header>
|
||||||
@@ -45,7 +64,7 @@
|
|||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</TreeViewItem.ItemTemplate>
|
</TreeViewItem.ItemTemplate>
|
||||||
</TreeViewItem>
|
</TreeViewItem>
|
||||||
<TreeViewItem ItemsSource="{Binding VoxelMaps}">
|
<TreeViewItem ItemsSource="{Binding VoxelMaps.Values}">
|
||||||
<TreeViewItem.Header>
|
<TreeViewItem.Header>
|
||||||
<TextBlock Text="{Binding VoxelMaps.Count, StringFormat=Voxel Maps ({0})}" />
|
<TextBlock Text="{Binding VoxelMaps.Count, StringFormat=Voxel Maps ({0})}" />
|
||||||
</TreeViewItem.Header>
|
</TreeViewItem.Header>
|
||||||
@@ -55,7 +74,7 @@
|
|||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</TreeViewItem.ItemTemplate>
|
</TreeViewItem.ItemTemplate>
|
||||||
</TreeViewItem>
|
</TreeViewItem>
|
||||||
<TreeViewItem ItemsSource="{Binding FloatingObjects}">
|
<TreeViewItem ItemsSource="{Binding FloatingObjects.Values}">
|
||||||
<TreeViewItem.Header>
|
<TreeViewItem.Header>
|
||||||
<TextBlock Text="{Binding FloatingObjects.Count, StringFormat=Floating Objects ({0})}" />
|
<TextBlock Text="{Binding FloatingObjects.Count, StringFormat=Floating Objects ({0})}" />
|
||||||
</TreeViewItem.Header>
|
</TreeViewItem.Header>
|
||||||
@@ -73,5 +92,6 @@
|
|||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Frame Grid.Column="1" x:Name="EditorFrame" Margin="3" NavigationUIVisibility="Hidden" />
|
<Frame Grid.Column="1" x:Name="EditorFrame" Margin="3" NavigationUIVisibility="Hidden" />
|
||||||
|
<GridSplitter Grid.Column="1" HorizontalAlignment="Left" VerticalAlignment="Stretch" ShowsPreview="True" Width="2" />
|
||||||
</Grid>
|
</Grid>
|
||||||
</UserControl>
|
</UserControl>
|
@@ -48,6 +48,8 @@ namespace Torch.Server.Views
|
|||||||
EditorFrame.Content = new BlockView {DataContext = bvm};
|
EditorFrame.Content = new BlockView {DataContext = bvm};
|
||||||
if (e.NewValue is VoxelMapViewModel vvm)
|
if (e.NewValue is VoxelMapViewModel vvm)
|
||||||
EditorFrame.Content = new VoxelMapView {DataContext = vvm};
|
EditorFrame.Content = new VoxelMapView {DataContext = vvm};
|
||||||
|
if (e.NewValue is CharacterViewModel cvm)
|
||||||
|
EditorFrame.Content = new CharacterView {DataContext = cvm};
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@@ -1,30 +0,0 @@
|
|||||||
<Window x:Class="Torch.Server.Views.FirstTimeSetup"
|
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
|
||||||
xmlns:local="clr-namespace:Torch.Server.Views"
|
|
||||||
xmlns:torch="clr-namespace:Torch;assembly=Torch"
|
|
||||||
xmlns:server="clr-namespace:Torch.Server"
|
|
||||||
mc:Ignorable="d"
|
|
||||||
Title="Torch First Time Setup" Height="200" Width="500">
|
|
||||||
<Window.DataContext>
|
|
||||||
<server:TorchConfig/>
|
|
||||||
</Window.DataContext>
|
|
||||||
<StackPanel>
|
|
||||||
<DockPanel ToolTip="This should be set to the folder that contains your mods and saves.">
|
|
||||||
<Label Content="Instance Path:" Width="150"/>
|
|
||||||
<TextBox Text="{Binding InstancePath}" Margin="3"/>
|
|
||||||
</DockPanel>
|
|
||||||
<DockPanel ToolTip="The name of your instance, this doesn't really matter.">
|
|
||||||
<Label Content="Instance Name:" Width="150"/>
|
|
||||||
<TextBox Text="{Binding InstanceName}" Margin="3"></TextBox>
|
|
||||||
</DockPanel>
|
|
||||||
<DockPanel ToolTip="This enables/disables automatic plugin updating.">
|
|
||||||
<Label Content="Automatic Plugin Updates:" Width="150"/>
|
|
||||||
<CheckBox IsChecked="{Binding EnableAutomaticUpdates}" VerticalAlignment="Center" Margin="3"/>
|
|
||||||
</DockPanel>
|
|
||||||
<Label Content="You can change these settings later by editing TorchConfig.xml"/>
|
|
||||||
<Button Content="Done" Margin="3" Click="ButtonBase_OnClick"></Button>
|
|
||||||
</StackPanel>
|
|
||||||
</Window>
|
|
@@ -3,7 +3,6 @@
|
|||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:local="clr-namespace:Torch.Server"
|
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d">
|
||||||
<StackPanel Margin="0,0,0,0" Orientation="Vertical">
|
<StackPanel Margin="0,0,0,0" Orientation="Vertical">
|
||||||
<Label Content="Mods" Margin="5,5,5,5"/>
|
<Label Content="Mods" Margin="5,5,5,5"/>
|
||||||
|
@@ -15,7 +15,6 @@ using System.Windows.Media.Imaging;
|
|||||||
using System.Windows.Navigation;
|
using System.Windows.Navigation;
|
||||||
using System.Windows.Shapes;
|
using System.Windows.Shapes;
|
||||||
using Sandbox.Engine.Networking;
|
using Sandbox.Engine.Networking;
|
||||||
using SteamSDK;
|
|
||||||
using VRage.Game;
|
using VRage.Game;
|
||||||
|
|
||||||
namespace Torch.Server
|
namespace Torch.Server
|
||||||
@@ -45,16 +44,16 @@ namespace Torch.Server
|
|||||||
mods = dialog.Result;
|
mods = dialog.Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var id in mods)
|
//foreach (var id in mods)
|
||||||
{
|
//{
|
||||||
var details = SteamHelper.GetItemDetails(id);
|
// var details = SteamHelper.GetItemDetails(id);
|
||||||
if (details.FileType != WorkshopFileType.Community)
|
// if (details.FileType != WorkshopFileType.Community)
|
||||||
continue;
|
// continue;
|
||||||
|
|
||||||
var item = SteamHelper.GetModItem(details);
|
// var item = SteamHelper.GetModItem(details);
|
||||||
var desc = details.Description.Length < 500 ? details.Description : details.Description.Substring(0, 500);
|
// var desc = details.Description.Length < 500 ? details.Description : details.Description.Substring(0, 500);
|
||||||
ModList.Items.Add(new ModViewModel(item, desc));
|
// ModList.Items.Add(new ModViewModel(item, desc));
|
||||||
}
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void modList_OnMouseDoubleClick(object sender, MouseButtonEventArgs e)
|
private void modList_OnMouseDoubleClick(object sender, MouseButtonEventArgs e)
|
||||||
|
@@ -3,7 +3,6 @@
|
|||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:local="clr-namespace:Torch.Server"
|
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d">
|
||||||
<DockPanel>
|
<DockPanel>
|
||||||
<StackPanel DockPanel.Dock="Bottom">
|
<StackPanel DockPanel.Dock="Bottom">
|
||||||
|
@@ -19,7 +19,6 @@ using Sandbox.Engine.Multiplayer;
|
|||||||
using Sandbox.Game.Multiplayer;
|
using Sandbox.Game.Multiplayer;
|
||||||
using Sandbox.Game.World;
|
using Sandbox.Game.World;
|
||||||
using Sandbox.ModAPI;
|
using Sandbox.ModAPI;
|
||||||
using SteamSDK;
|
|
||||||
using Torch.API;
|
using Torch.API;
|
||||||
using Torch.API.Managers;
|
using Torch.API.Managers;
|
||||||
using Torch.API.Session;
|
using Torch.API.Session;
|
||||||
@@ -47,8 +46,12 @@ namespace Torch.Server
|
|||||||
public void BindServer(ITorchServer server)
|
public void BindServer(ITorchServer server)
|
||||||
{
|
{
|
||||||
_server = server;
|
_server = server;
|
||||||
|
_server.Initialized += Server_Initialized ;
|
||||||
|
}
|
||||||
|
|
||||||
var sessionManager = server.Managers.GetManager<ITorchSessionManager>();
|
private void Server_Initialized(ITorchServer obj)
|
||||||
|
{
|
||||||
|
var sessionManager = _server.Managers.GetManager<ITorchSessionManager>();
|
||||||
sessionManager.SessionStateChanged += SessionStateChanged;
|
sessionManager.SessionStateChanged += SessionStateChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -3,7 +3,6 @@
|
|||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:local="clr-namespace:Torch.Server.Views"
|
|
||||||
xmlns:viewModels="clr-namespace:Torch.Server.ViewModels"
|
xmlns:viewModels="clr-namespace:Torch.Server.ViewModels"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
d:DesignHeight="300" d:DesignWidth="300">
|
d:DesignHeight="300" d:DesignWidth="300">
|
||||||
@@ -29,7 +28,9 @@
|
|||||||
</ListView>
|
</ListView>
|
||||||
<Button Grid.Row="1" Content="Open Folder" Margin="3" DockPanel.Dock="Bottom" Click="OpenFolder_OnClick"/>
|
<Button Grid.Row="1" Content="Open Folder" Margin="3" DockPanel.Dock="Bottom" Click="OpenFolder_OnClick"/>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Frame Grid.Column="1" NavigationUIVisibility="Hidden" Content="{Binding SelectedPlugin.Control}"/>
|
<ScrollViewer Name="PScroll" Grid.Column="1" Margin="3">
|
||||||
|
<Frame NavigationUIVisibility="Hidden" Content="{Binding SelectedPlugin.Control}"/>
|
||||||
|
</ScrollViewer>
|
||||||
</Grid>
|
</Grid>
|
||||||
</UserControl>
|
</UserControl>
|
||||||
|
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
|
using System.ComponentModel;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
@@ -19,6 +20,7 @@ using Torch.API;
|
|||||||
using Torch.API.Managers;
|
using Torch.API.Managers;
|
||||||
using Torch.Managers;
|
using Torch.Managers;
|
||||||
using Torch.Server.ViewModels;
|
using Torch.Server.ViewModels;
|
||||||
|
using Torch.Views;
|
||||||
|
|
||||||
namespace Torch.Server.Views
|
namespace Torch.Server.Views
|
||||||
{
|
{
|
||||||
@@ -35,17 +37,39 @@ namespace Torch.Server.Views
|
|||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void PluginManagerOnPropertyChanged(object sender, PropertyChangedEventArgs propertyChangedEventArgs)
|
||||||
|
{
|
||||||
|
if (propertyChangedEventArgs.PropertyName == nameof(PluginManagerViewModel.SelectedPlugin))
|
||||||
|
{
|
||||||
|
if (((PluginManagerViewModel)DataContext).SelectedPlugin.Control is PropertyGrid)
|
||||||
|
PScroll.VerticalScrollBarVisibility = ScrollBarVisibility.Disabled;
|
||||||
|
else
|
||||||
|
PScroll.VerticalScrollBarVisibility = ScrollBarVisibility.Auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void BindServer(ITorchServer server)
|
public void BindServer(ITorchServer server)
|
||||||
{
|
{
|
||||||
_server = server;
|
_server = server;
|
||||||
_plugins = _server.Managers.GetManager<PluginManager>();
|
_server.Initialized += Server_Initialized;
|
||||||
var pluginManager = new PluginManagerViewModel(_plugins);
|
}
|
||||||
DataContext = pluginManager;
|
|
||||||
|
private void Server_Initialized(ITorchServer obj)
|
||||||
|
{
|
||||||
|
Dispatcher.InvokeAsync(() =>
|
||||||
|
{
|
||||||
|
_plugins = _server.Managers.GetManager<PluginManager>();
|
||||||
|
var pluginManager = new PluginManagerViewModel(_plugins);
|
||||||
|
DataContext = pluginManager;
|
||||||
|
pluginManager.PropertyChanged += PluginManagerOnPropertyChanged;
|
||||||
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OpenFolder_OnClick(object sender, RoutedEventArgs e)
|
private void OpenFolder_OnClick(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
Process.Start("explorer.exe", _plugins.PluginDir);
|
if (_plugins?.PluginDir != null)
|
||||||
|
Process.Start(_plugins.PluginDir);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,15 +0,0 @@
|
|||||||
<UserControl x:Class="Torch.Server.Views.PropertyGrid"
|
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
|
||||||
xmlns:local="clr-namespace:Torch.Server.Views"
|
|
||||||
mc:Ignorable="d"
|
|
||||||
d:DesignHeight="300" d:DesignWidth="300">
|
|
||||||
<DataGrid x:Name="Grid" AutoGenerateColumns="False">
|
|
||||||
<DataGrid.Columns>
|
|
||||||
<DataGridTextColumn x:Name="NameCol" Width="1*" Header="Name" Binding="{Binding Name}" IsReadOnly="True"/>
|
|
||||||
<DataGridTemplateColumn x:Name="ValCol" Width="1*" Header="Value"/>
|
|
||||||
</DataGrid.Columns>
|
|
||||||
</DataGrid>
|
|
||||||
</UserControl>
|
|
@@ -1,68 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Windows;
|
|
||||||
using System.Windows.Controls;
|
|
||||||
using System.Windows.Data;
|
|
||||||
using System.Windows.Documents;
|
|
||||||
using System.Windows.Input;
|
|
||||||
using System.Windows.Media;
|
|
||||||
using System.Windows.Media.Imaging;
|
|
||||||
using System.Windows.Navigation;
|
|
||||||
using System.Windows.Shapes;
|
|
||||||
|
|
||||||
namespace Torch.Server.Views
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Interaction logic for PropertyGrid.xaml
|
|
||||||
/// </summary>
|
|
||||||
public partial class PropertyGrid : UserControl
|
|
||||||
{
|
|
||||||
public PropertyGrid()
|
|
||||||
{
|
|
||||||
InitializeComponent();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetObject(object obj)
|
|
||||||
{
|
|
||||||
var props = obj.GetType().GetProperties();
|
|
||||||
foreach (var prop in props)
|
|
||||||
{
|
|
||||||
var p = prop.GetValue(obj);
|
|
||||||
Grid.Items.Add(new PropertyView(p, prop.Name));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class PropertyView : ViewModel
|
|
||||||
{
|
|
||||||
private object _obj;
|
|
||||||
|
|
||||||
public string Name { get; }
|
|
||||||
public string Value { get { return _obj.ToString(); } }
|
|
||||||
public DataTemplate ValueEditTemplate;
|
|
||||||
|
|
||||||
public PropertyView(object obj, string name)
|
|
||||||
{
|
|
||||||
Name = name;
|
|
||||||
_obj = obj;
|
|
||||||
|
|
||||||
ValueEditTemplate = new DataTemplate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
public class PropertyGridDataTemplateSelector : DataTemplateSelector
|
|
||||||
{
|
|
||||||
public override DataTemplate SelectTemplate(object item, DependencyObject container)
|
|
||||||
{
|
|
||||||
if (item is IEnumerable)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
}
|
|
22
Torch.Server/Views/Resources.xaml
Normal file
22
Torch.Server/Views/Resources.xaml
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:converters="clr-namespace:Torch.Server.Views.Converters"
|
||||||
|
xmlns:system="clr-namespace:System;assembly=mscorlib">
|
||||||
|
<Style x:Key="{x:Type Window}" TargetType="{x:Type Window}" BasedOn="{StaticResource {x:Type Window}}">
|
||||||
|
<Style.Setters>
|
||||||
|
<Setter Property="Background" Value="Black"/>
|
||||||
|
</Style.Setters>
|
||||||
|
</Style>
|
||||||
|
<Style x:Key="ValidatedTextBox" TargetType="{x:Type TextBox}">
|
||||||
|
<Style.Triggers>
|
||||||
|
<Trigger Property="Validation.HasError" Value="True">
|
||||||
|
<Setter Property="ToolTip"
|
||||||
|
Value="{Binding RelativeSource={RelativeSource Self}, Path=(Validation.Errors)[0].ErrorContent}" />
|
||||||
|
<Setter Property="Background" Value="Pink"/>
|
||||||
|
</Trigger>
|
||||||
|
</Style.Triggers>
|
||||||
|
</Style>
|
||||||
|
<converters:ListConverter x:Key="ListConverterString" Type="system:String"/>
|
||||||
|
<converters:ListConverter x:Key="ListConverterUInt64" Type="system:UInt64"/>
|
||||||
|
<converters:BooleanAndConverter x:Key="BooleanAndConverter"/>
|
||||||
|
</ResourceDictionary>
|
188
Torch.Server/Views/SessionSettingsView.xaml
Normal file
188
Torch.Server/Views/SessionSettingsView.xaml
Normal file
@@ -0,0 +1,188 @@
|
|||||||
|
<UserControl x:Class="Torch.Server.Views.SessionSettingsView"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
d:DesignHeight="300" d:DesignWidth="300">
|
||||||
|
<StackPanel>
|
||||||
|
<Expander Header="Block Limits">
|
||||||
|
<StackPanel Margin="10,0,0,0">
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<TextBox Text="{Binding MaxBlocksPerPlayer}" Margin="3" Width="70" />
|
||||||
|
<Label Content="Max Blocks Per Player" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<TextBox Text="{Binding MaxGridSize}" Margin="3" Width="70" />
|
||||||
|
<Label Content="Max Grid Size" />
|
||||||
|
</StackPanel>
|
||||||
|
<Button Content="Add" Margin="3" Click="AddLimit_OnClick" />
|
||||||
|
<ListView ItemsSource="{Binding BlockTypeLimits.Dictionary}" Margin="3">
|
||||||
|
<ListView.ItemTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<Label Content="{Binding Key, Mode=OneTime}" Width="150" Margin="3" />
|
||||||
|
<TextBox Text="{Binding Value, Mode=OneTime}" Width="50" Margin="3" />
|
||||||
|
<Button Content=" X " Margin="3" Click="RemoveLimit_OnClick" />
|
||||||
|
</StackPanel>
|
||||||
|
</DataTemplate>
|
||||||
|
</ListView.ItemTemplate>
|
||||||
|
</ListView>
|
||||||
|
</StackPanel>
|
||||||
|
</Expander>
|
||||||
|
<Expander Header="Multipliers">
|
||||||
|
<StackPanel Margin="10,0,0,0">
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<TextBox Text="{Binding InventorySizeMultiplier}" Margin="3" Width="70" />
|
||||||
|
<Label Content="Inventory Size" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<TextBox Text="{Binding RefinerySpeedMultiplier}" Margin="3" Width="70" />
|
||||||
|
<Label Content="Refinery Speed" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<TextBox Text="{Binding AssemblerEfficiencyMultiplier}" Margin="3" Width="70" />
|
||||||
|
<Label Content="Assembler Efficiency" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<TextBox Text="{Binding AssemblerSpeedMultiplier}" Margin="3" Width="70" />
|
||||||
|
<Label Content="Assembler Speed" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<TextBox Text="{Binding WelderSpeedMultiplier}" Margin="3" Width="70" />
|
||||||
|
<Label Content="Welder Speed" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<TextBox Text="{Binding GrinderSpeedMultiplier}" Margin="3" Width="70" />
|
||||||
|
<Label Content="Grinder Speed" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<TextBox Text="{Binding HackSpeedMultiplier}" Margin="3" Width="70" />
|
||||||
|
<Label Content="Hacking Speed" />
|
||||||
|
</StackPanel>
|
||||||
|
</StackPanel>
|
||||||
|
</Expander>
|
||||||
|
<Expander Header="NPCs">
|
||||||
|
<StackPanel Margin="10,0,0,0">
|
||||||
|
<CheckBox IsChecked="{Binding EnableDrones}" Content="Enable Drones" Margin="3" />
|
||||||
|
<CheckBox IsChecked="{Binding EnableEncounters}" Content="Enable Encounters" Margin="3" />
|
||||||
|
<CheckBox IsChecked="{Binding EnableSpiders}" Content="Enable Spiders" Margin="3" />
|
||||||
|
<CheckBox IsChecked="{Binding EnableWolfs}" Content="Enable Wolves" Margin="3" />
|
||||||
|
<CheckBox IsChecked="{Binding CargoShipsEnabled}" Content="Enable Cargo Ships" Margin="3" />
|
||||||
|
</StackPanel>
|
||||||
|
</Expander>
|
||||||
|
<Expander Header="Environment">
|
||||||
|
<StackPanel Margin="10,0,0,0">
|
||||||
|
<StackPanel Orientation="Horizontal" ToolTip="Increases physics precision at the cost of performance.">
|
||||||
|
<TextBox Text="{Binding PhysicsIterations}" Margin="3" Width="70" />
|
||||||
|
<Label Content="Physics Iterations" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<TextBox Text="{Binding MaxFloatingObjects}" Margin="3" Width="70" />
|
||||||
|
<Label Content="Max Floating Objects" />
|
||||||
|
</StackPanel>
|
||||||
|
<CheckBox IsChecked="{Binding RealisticSound}" Content="Enable Realistic Sound"
|
||||||
|
Margin="3" />
|
||||||
|
<CheckBox IsChecked="{Binding EnableOxygenPressurization}" Content="Enable Airtightness" Margin="3" />
|
||||||
|
<CheckBox IsChecked="{Binding EnableOxygen}" Content="Enable Oxygen" Margin="3" />
|
||||||
|
<CheckBox IsChecked="{Binding DestructibleBlocks}"
|
||||||
|
Content="Enable Destructible Blocks" Margin="3" />
|
||||||
|
<CheckBox IsChecked="{Binding EnableToolShake}" Content="Enable Tool Shake" Margin="3" />
|
||||||
|
<CheckBox IsChecked="{Binding EnableVoxelDestruction}" Content="Enable Voxel Destruction"
|
||||||
|
Margin="3" />
|
||||||
|
<CheckBox IsChecked="{Binding EnableSunRotation}" Content="Enable Sun Rotation" Margin="3" />
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<TextBox Text="{Binding SunRotationIntervalMinutes}" Margin="3" Width="70" />
|
||||||
|
<Label Content="Sun Rotation Interval (mins)" />
|
||||||
|
</StackPanel>
|
||||||
|
<CheckBox IsChecked="{Binding EnableFlora}" Content="Enable Flora" Margin="3" />
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<TextBox Text="{Binding FloraDensity}" Margin="3" Width="70" />
|
||||||
|
<Label Content="Flora Density" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<TextBox Text="{Binding FloraDensityMultiplier}" Margin="3" Width="70" />
|
||||||
|
<Label Content="Flora Density Multiplier" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<TextBox Text="{Binding ViewDistance}" Margin="3" Width="70" />
|
||||||
|
<Label Content="View Distance (meters)" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<TextBox Text="{Binding WorldSizeKm}" Margin="3" Width="70" />
|
||||||
|
<Label Content="World Size (km)" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<ComboBox SelectedItem="{Binding EnvironmentHostility}"
|
||||||
|
ItemsSource="{Binding EnvironmentHostilityValues}" Margin="3" Width="100"
|
||||||
|
DockPanel.Dock="Left" />
|
||||||
|
<Label Content="Environment Hostility" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<TextBox Text="{Binding ProceduralDensity}" Margin="3" Width="70" />
|
||||||
|
<Label Content="Procedural Density" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<TextBox Text="{Binding ProceduralSeed}" Margin="3" Width="70" />
|
||||||
|
<Label Content="Procedural Seed" />
|
||||||
|
</StackPanel>
|
||||||
|
</StackPanel>
|
||||||
|
</Expander>
|
||||||
|
<Expander Header="Players">
|
||||||
|
<StackPanel Margin="10,0,0,0">
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<TextBox Text="{Binding MaxPlayers}" Margin="3" Width="70" />
|
||||||
|
<Label Content="Max Players" />
|
||||||
|
</StackPanel>
|
||||||
|
<CheckBox IsChecked="{Binding Enable3rdPersonView}" Content="Enable 3rd Person Camera"
|
||||||
|
Margin="3" />
|
||||||
|
<CheckBox IsChecked="{Binding EnableJetpack}" Content="Enable Jetpack" Margin="3" />
|
||||||
|
<CheckBox IsChecked="{Binding AutoHealing}" Content="Auto Healing" Margin="3" />
|
||||||
|
<CheckBox IsChecked="{Binding EnableCopyPaste}" Content="Enable Copy/Paste" Margin="3" />
|
||||||
|
<CheckBox IsChecked="{Binding ShowPlayerNamesOnHud}" Content="Show Player Names on HUD"
|
||||||
|
Margin="3" />
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<TextBox Text="{Binding SpawnShipTimeMultiplier}" Margin="3" Width="70" />
|
||||||
|
<Label Content="Respawn Time Multiplier" />
|
||||||
|
</StackPanel>
|
||||||
|
<CheckBox IsChecked="{Binding ResetOwnership}" Content="Reset Ownership" Margin="3" />
|
||||||
|
<CheckBox IsChecked="{Binding SpawnWithTools}" Content="Spawn With Tools" Margin="3" />
|
||||||
|
</StackPanel>
|
||||||
|
</Expander>
|
||||||
|
<Expander Header="Miscellaneous">
|
||||||
|
<StackPanel Margin="10,0,0,0">
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<TextBox Text="{Binding AutoSaveInMinutes}" Margin="3" Width="70" />
|
||||||
|
<Label Content="Autosave Interval (minutes)" />
|
||||||
|
</StackPanel>
|
||||||
|
<CheckBox IsChecked="{Binding EnableConvertToStation}" Content="Enable Convert to Station"
|
||||||
|
Margin="3" />
|
||||||
|
|
||||||
|
<CheckBox IsChecked="{Binding EnableRemoteBlockRemoval}"
|
||||||
|
Content="Enable Remote Ownership Removal" Margin="3" />
|
||||||
|
<CheckBox IsChecked="{Binding EnableRespawnShips}" Content="Enable Respawn Ships"
|
||||||
|
Margin="3" />
|
||||||
|
<CheckBox IsChecked="{Binding EnableScripterRole}" Content="Enable Scripter Role"
|
||||||
|
Margin="3" />
|
||||||
|
<CheckBox IsChecked="{Binding EnableSpectator}" Content="Enable Spectator Camera"
|
||||||
|
Margin="3" />
|
||||||
|
<CheckBox IsChecked="{Binding RespawnShipDelete}" Content="Remove Respawn Ships on Logoff"
|
||||||
|
Margin="3" />
|
||||||
|
<CheckBox IsChecked="{Binding ThrusterDamage}" Content="Enable Thruster Damage"
|
||||||
|
Margin="3" />
|
||||||
|
<CheckBox IsChecked="{Binding WeaponsEnabled}" Content="Enable Weapons" Margin="3" />
|
||||||
|
<CheckBox IsChecked="{Binding EnableIngameScripts}" Content="Enable Ingame Scripts"
|
||||||
|
Margin="3" />
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<ComboBox SelectedItem="{Binding GameMode}" ItemsSource="{Binding GameModeValues}"
|
||||||
|
Margin="3" Width="100" DockPanel.Dock="Left" />
|
||||||
|
<Label Content="Game Mode" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<TextBox Text="{Binding MaxBackupSaves}" Margin="3" Width="70" />
|
||||||
|
<Label Content="Max Backup Saves" />
|
||||||
|
</StackPanel>
|
||||||
|
</StackPanel>
|
||||||
|
</Expander>
|
||||||
|
</StackPanel>
|
||||||
|
</UserControl>
|
40
Torch.Server/Views/SessionSettingsView.xaml.cs
Normal file
40
Torch.Server/Views/SessionSettingsView.xaml.cs
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
using System.Windows.Data;
|
||||||
|
using System.Windows.Documents;
|
||||||
|
using System.Windows.Input;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using System.Windows.Media.Imaging;
|
||||||
|
using System.Windows.Navigation;
|
||||||
|
using System.Windows.Shapes;
|
||||||
|
using Torch.Server.ViewModels;
|
||||||
|
|
||||||
|
namespace Torch.Server.Views
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interaction logic for SessionSettingsView.xaml
|
||||||
|
/// </summary>
|
||||||
|
public partial class SessionSettingsView : UserControl
|
||||||
|
{
|
||||||
|
public SessionSettingsView()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RemoveLimit_OnClick(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
var vm = (BlockLimitViewModel)((Button)sender).DataContext;
|
||||||
|
//_instanceManager.DedicatedConfig.SessionSettings.BlockLimits.Remove(vm);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddLimit_OnClick(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
//_instanceManager.DedicatedConfig.SessionSettings.BlockLimits.Add(new BlockLimitViewModel(_instanceManager.DedicatedConfig.SessionSettings, "", 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
31
Torch.Server/Views/ThemeControl.xaml
Normal file
31
Torch.Server/Views/ThemeControl.xaml
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
<UserControl x:Class="Torch.Server.Views.ThemeControl"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:viewModels="clr-namespace:Torch.Server.ViewModels"
|
||||||
|
xmlns:managers="clr-namespace:Torch.Server.Managers"
|
||||||
|
xmlns:system="clr-namespace:System;assembly=mscorlib"
|
||||||
|
xmlns:validationRules="clr-namespace:Torch.Server.Views.ValidationRules"
|
||||||
|
xmlns:views="clr-namespace:Torch.Views;assembly=Torch"
|
||||||
|
mc:Ignorable="d">
|
||||||
|
<Grid>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
|
<DockPanel Grid.Row="0">
|
||||||
|
<Label Content="Theme:" DockPanel.Dock="Left" />
|
||||||
|
<ComboBox ItemsSource="{Binding Themes}"
|
||||||
|
SelectionChanged="Selector_OnSelectionChanged">
|
||||||
|
</ComboBox>
|
||||||
|
</DockPanel>
|
||||||
|
|
||||||
|
<TextBlock Width="Auto" Grid.Row="1" HorizontalAlignment="Right" VerticalAlignment="Bottom" Name="LegalshtuffBlock">
|
||||||
|
<Hyperlink Name="LegalshtuffLink" RequestNavigate="Hyperlink_RequestNavigate">
|
||||||
|
Theme License
|
||||||
|
</Hyperlink>
|
||||||
|
</TextBlock>
|
||||||
|
</Grid>
|
||||||
|
</UserControl>
|
107
Torch.Server/Views/ThemeControl.xaml.cs
Normal file
107
Torch.Server/Views/ThemeControl.xaml.cs
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Windows.Navigation;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
using System.Windows.Data;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using System.Windows.Threading;
|
||||||
|
using Torch.API.Managers;
|
||||||
|
using Torch.API.Plugins;
|
||||||
|
using Torch.Server.Annotations;
|
||||||
|
using Torch.Server.Managers;
|
||||||
|
using Torch.Server.ViewModels;
|
||||||
|
|
||||||
|
namespace Torch.Server.Views
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interaction logic for ThemeControl.xaml
|
||||||
|
/// </summary>
|
||||||
|
public partial class ThemeControl : UserControl, INotifyPropertyChanged
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Action other views can subscribe to to update their views if they dont inherit the style from the window for some reason.
|
||||||
|
/// </summary>
|
||||||
|
public static Action<ResourceDictionary> UpdateDynamicControls;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Current theme other views can set their theme to when they first spawn
|
||||||
|
/// </summary>
|
||||||
|
public static ResourceDictionary currentTheme = new ResourceDictionary() { Source = new Uri(@"/Views/Resources.xaml", UriKind.Relative) };
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The current torch window and config.
|
||||||
|
/// </summary>
|
||||||
|
public TorchUI uiSource;
|
||||||
|
private TorchConfig _torchConfig;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// List of available themes
|
||||||
|
/// </summary>
|
||||||
|
public List<string> Themes
|
||||||
|
{
|
||||||
|
get => _themes.Keys.ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Dictionary<string, ResourceDictionary> _themes = new Dictionary<string, ResourceDictionary>();
|
||||||
|
private HashSet<ITorchPlugin> plugins;
|
||||||
|
|
||||||
|
public event PropertyChangedEventHandler PropertyChanged;
|
||||||
|
|
||||||
|
public ThemeControl()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
this.DataContext = this;
|
||||||
|
|
||||||
|
_themes["Dark theme"] = new ResourceDictionary() { Source = new Uri(@"/Themes/Dark Theme.xaml", UriKind.Relative) };
|
||||||
|
_themes["Animated Dark theme"] = new ResourceDictionary() { Source = new Uri(@"/Themes/Dark Theme Animated.xaml", UriKind.Relative) };
|
||||||
|
|
||||||
|
_themes["Light theme"] = new ResourceDictionary() { Source = new Uri(@"/Themes/Light Theme.xaml", UriKind.Relative) };
|
||||||
|
_themes["Light theme animated"] = new ResourceDictionary() { Source = new Uri(@"/Themes/Light Theme Animated.xaml", UriKind.Relative) };
|
||||||
|
|
||||||
|
_themes["Torch Theme"] = new ResourceDictionary() { Source = new Uri(@"/Views/Resources.xaml", UriKind.Relative) };
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Selector_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||||
|
{
|
||||||
|
ComboBox box = (ComboBox)sender;
|
||||||
|
var boxText = box.SelectedItem.ToString();
|
||||||
|
|
||||||
|
ChangeTheme(_themes[boxText].Source);
|
||||||
|
|
||||||
|
if (_torchConfig != null)
|
||||||
|
{
|
||||||
|
_torchConfig.LastUsedTheme = boxText;
|
||||||
|
_torchConfig.Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ChangeTheme(Uri uri)
|
||||||
|
{
|
||||||
|
uiSource.Resources.MergedDictionaries.Clear();
|
||||||
|
var resource = new ResourceDictionary() { Source = uri };
|
||||||
|
uiSource.Resources.MergedDictionaries.Add(resource);
|
||||||
|
UpdateDynamicControls?.Invoke(resource);
|
||||||
|
currentTheme = resource;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Hyperlink_RequestNavigate(object sender, RequestNavigateEventArgs e)
|
||||||
|
{
|
||||||
|
Process.Start(new ProcessStartInfo(e.Uri.AbsoluteUri));
|
||||||
|
e.Handled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetConfig(TorchConfig config)
|
||||||
|
{
|
||||||
|
_torchConfig = config;
|
||||||
|
|
||||||
|
if (_themes.ContainsKey(config.LastUsedTheme))
|
||||||
|
ChangeTheme(_themes[config.LastUsedTheme].Source);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -7,20 +7,39 @@
|
|||||||
xmlns:views="clr-namespace:Torch.Server.Views"
|
xmlns:views="clr-namespace:Torch.Server.Views"
|
||||||
xmlns:converters="clr-namespace:Torch.Server.Views.Converters"
|
xmlns:converters="clr-namespace:Torch.Server.Views.Converters"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
Title="Torch">
|
Title="Torch"
|
||||||
|
Name="MainWindow">
|
||||||
<Window.Resources>
|
<Window.Resources>
|
||||||
<converters:InverseBooleanConverter x:Key="InverseBool"/>
|
<ResourceDictionary>
|
||||||
|
<ResourceDictionary.MergedDictionaries>
|
||||||
|
<ResourceDictionary Source="Resources.xaml"/>
|
||||||
|
</ResourceDictionary.MergedDictionaries>
|
||||||
|
<converters:InverseBooleanConverter x:Key="InverseBool"/>
|
||||||
|
</ResourceDictionary>
|
||||||
</Window.Resources>
|
</Window.Resources>
|
||||||
|
<!--
|
||||||
|
<Window.DataContext>
|
||||||
|
<local:TorchServer/>
|
||||||
|
</Window.DataContext>
|
||||||
|
-->
|
||||||
<Grid>
|
<Grid>
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto"></RowDefinition>
|
||||||
<RowDefinition Height="Auto"/>
|
<RowDefinition Height="Auto"/>
|
||||||
<RowDefinition/>
|
<RowDefinition/>
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<StackPanel Grid.Row="0" Margin="5,5,5,5" Orientation="Horizontal">
|
<StackPanel Grid.Row="1" Margin="5,5,5,5" Orientation="Horizontal">
|
||||||
<Button x:Name="BtnStart" Content="Start" Height="24" Width="75" Margin="5,0,5,0"
|
<Button x:Name="BtnStart" Content="Start" Height="24" Width="75" Margin="5,0,5,0"
|
||||||
HorizontalAlignment="Left" Click="BtnStart_Click" IsEnabled="{Binding IsRunning, Converter={StaticResource InverseBool}}"/>
|
HorizontalAlignment="Left" Click="BtnStart_Click">
|
||||||
|
<Button.IsEnabled>
|
||||||
|
<MultiBinding Converter="{StaticResource BooleanAndConverter}">
|
||||||
|
<Binding ElementName="MainWindow" Path="DataContext.CanRun"/>
|
||||||
|
<Binding ElementName="ConfigControl" Path="ConfigValid"/>
|
||||||
|
</MultiBinding>
|
||||||
|
</Button.IsEnabled>
|
||||||
|
</Button>
|
||||||
<Button x:Name="BtnStop" Content="Stop" Height="24" Width="75" Margin="5,0,5,0" HorizontalAlignment="Left"
|
<Button x:Name="BtnStop" Content="Stop" Height="24" Width="75" Margin="5,0,5,0" HorizontalAlignment="Left"
|
||||||
Click="BtnStop_Click" IsEnabled="{Binding IsRunning}" />
|
Click="BtnStop_Click" IsEnabled="{Binding IsRunning}"/>
|
||||||
<Label>
|
<Label>
|
||||||
<Label.Content>
|
<Label.Content>
|
||||||
<TextBlock Text="{Binding State, StringFormat=Status: {0}}"></TextBlock>
|
<TextBlock Text="{Binding State, StringFormat=Status: {0}}"></TextBlock>
|
||||||
@@ -36,10 +55,18 @@
|
|||||||
<TextBlock Text="{Binding ElapsedPlayTime, StringFormat=Uptime: {0:g}}"/>
|
<TextBlock Text="{Binding ElapsedPlayTime, StringFormat=Uptime: {0:g}}"/>
|
||||||
</Label.Content>
|
</Label.Content>
|
||||||
</Label>
|
</Label>
|
||||||
|
<Label x:Name="LabelPlayers">
|
||||||
|
<Label.Content>
|
||||||
|
<TextBlock ></TextBlock>
|
||||||
|
</Label.Content>
|
||||||
|
</Label>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<TabControl Grid.Row="1" Height="Auto" x:Name="TabControl" Margin="5,0,5,5">
|
<TabControl Grid.Row="2" Height="Auto" x:Name="TabControl" Margin="5,10,5,5">
|
||||||
|
<TabItem Header="Log">
|
||||||
|
<RichTextBox x:Name="ConsoleText" VerticalScrollBarVisibility="Visible" FontFamily="Consolas" IsReadOnly="True"/>
|
||||||
|
</TabItem>
|
||||||
<TabItem Header="Configuration">
|
<TabItem Header="Configuration">
|
||||||
<Grid IsEnabled="{Binding IsRunning, Converter={StaticResource InverseBool}}">
|
<Grid IsEnabled="{Binding CanRun}">
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="Auto"/>
|
<RowDefinition Height="Auto"/>
|
||||||
<RowDefinition/>
|
<RowDefinition/>
|
||||||
@@ -49,11 +76,8 @@
|
|||||||
<ColumnDefinition Width="Auto"/>
|
<ColumnDefinition Width="Auto"/>
|
||||||
<ColumnDefinition/>
|
<ColumnDefinition/>
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
<Label Grid.Column="0" Content="Instance Path: " Margin="3" />
|
|
||||||
<TextBox Grid.Column="1" x:Name="InstancePathBox" Margin="3" Height="20"
|
|
||||||
LostKeyboardFocus="InstancePathBox_OnLostKeyboardFocus" />
|
|
||||||
</Grid>
|
</Grid>
|
||||||
<views:ConfigControl Grid.Row="1" x:Name="ConfigControl" Margin="3" DockPanel.Dock="Bottom" IsEnabled="{Binding IsRunning, Converter={StaticResource InverseBool}}"/>
|
<views:ConfigControl Grid.Row="1" x:Name="ConfigControl" Margin="3" DockPanel.Dock="Bottom" IsEnabled="{Binding CanRun}"/>
|
||||||
</Grid>
|
</Grid>
|
||||||
</TabItem>
|
</TabItem>
|
||||||
<TabItem Header="Chat/Players">
|
<TabItem Header="Chat/Players">
|
||||||
@@ -72,6 +96,9 @@
|
|||||||
<TabItem Header="Plugins">
|
<TabItem Header="Plugins">
|
||||||
<views:PluginsControl x:Name="Plugins" />
|
<views:PluginsControl x:Name="Plugins" />
|
||||||
</TabItem>
|
</TabItem>
|
||||||
|
<TabItem Header="Themes">
|
||||||
|
<views:ThemeControl x:Name="Themes" />
|
||||||
|
</TabItem>
|
||||||
</TabControl>
|
</TabControl>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Window>
|
</Window>
|
@@ -1,10 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Timers;
|
using System.Timers;
|
||||||
@@ -13,14 +10,16 @@ using System.Windows.Controls;
|
|||||||
using System.Windows.Data;
|
using System.Windows.Data;
|
||||||
using System.Windows.Documents;
|
using System.Windows.Documents;
|
||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
using System.Windows.Media;
|
|
||||||
using System.Windows.Media.Imaging;
|
using System.Windows.Media.Imaging;
|
||||||
using System.Windows.Navigation;
|
using System.Windows.Navigation;
|
||||||
using System.Windows.Shapes;
|
using System.Windows.Shapes;
|
||||||
|
using NLog;
|
||||||
|
using NLog.Targets.Wrappers;
|
||||||
using Sandbox;
|
using Sandbox;
|
||||||
using Torch.API;
|
using Torch.API;
|
||||||
|
using Torch.API.Managers;
|
||||||
using Torch.Server.Managers;
|
using Torch.Server.Managers;
|
||||||
using Timer = System.Timers.Timer;
|
using MessageBoxResult = System.Windows.MessageBoxResult;
|
||||||
|
|
||||||
namespace Torch.Server
|
namespace Torch.Server
|
||||||
{
|
{
|
||||||
@@ -36,19 +35,38 @@ namespace Torch.Server
|
|||||||
{
|
{
|
||||||
_config = (TorchConfig)server.Config;
|
_config = (TorchConfig)server.Config;
|
||||||
_server = server;
|
_server = server;
|
||||||
|
//TODO: data binding for whole server
|
||||||
|
DataContext = server;
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
|
AttachConsole();
|
||||||
|
|
||||||
Left = _config.WindowPosition.X;
|
Left = _config.WindowPosition.X;
|
||||||
Top = _config.WindowPosition.Y;
|
Top = _config.WindowPosition.Y;
|
||||||
Width = _config.WindowSize.X;
|
Width = _config.WindowSize.X;
|
||||||
Height = _config.WindowSize.Y;
|
Height = _config.WindowSize.Y;
|
||||||
|
|
||||||
//TODO: data binding for whole server
|
|
||||||
DataContext = server;
|
|
||||||
Chat.BindServer(server);
|
Chat.BindServer(server);
|
||||||
PlayerList.BindServer(server);
|
PlayerList.BindServer(server);
|
||||||
Plugins.BindServer(server);
|
Plugins.BindServer(server);
|
||||||
LoadConfig((TorchConfig)server.Config);
|
LoadConfig((TorchConfig)server.Config);
|
||||||
|
|
||||||
|
Themes.uiSource = this;
|
||||||
|
Themes.SetConfig(_config);
|
||||||
|
Title = $"{_config.InstanceName} - Torch {server.TorchVersion}, SE {server.GameVersion}";
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AttachConsole()
|
||||||
|
{
|
||||||
|
const string target = "wpf";
|
||||||
|
var doc = LogManager.Configuration.FindTargetByName<FlowDocumentTarget>(target)?.Document;
|
||||||
|
if (doc == null)
|
||||||
|
{
|
||||||
|
var wrapped = LogManager.Configuration.FindTargetByName<WrapperTargetBase>(target);
|
||||||
|
doc = (wrapped?.WrappedTarget as FlowDocumentTarget)?.Document;
|
||||||
|
}
|
||||||
|
ConsoleText.Document = doc ?? new FlowDocument(new Paragraph(new Run("No target!")));
|
||||||
|
ConsoleText.TextChanged += (sender, args) => ConsoleText.ScrollToEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void LoadConfig(TorchConfig config)
|
public void LoadConfig(TorchConfig config)
|
||||||
@@ -59,19 +77,22 @@ namespace Torch.Server
|
|||||||
_config = config;
|
_config = config;
|
||||||
Dispatcher.Invoke(() =>
|
Dispatcher.Invoke(() =>
|
||||||
{
|
{
|
||||||
InstancePathBox.Text = config.InstancePath;
|
//InstancePathBox.Text = config.InstancePath;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void BtnStart_Click(object sender, RoutedEventArgs e)
|
private void BtnStart_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
_server.GetManager<InstanceManager>().SaveConfig();
|
_server.DedicatedInstance.SaveConfig();
|
||||||
_server.Start();
|
Task.Run(() => _server.Start());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void BtnStop_Click(object sender, RoutedEventArgs e)
|
private void BtnStop_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
_server.Stop();
|
var result = MessageBox.Show("Are you sure you want to stop the server?", "Stop Server", MessageBoxButton.YesNo);
|
||||||
|
|
||||||
|
if (result == MessageBoxResult.Yes)
|
||||||
|
_server.Invoke(() => _server.Stop());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnClosing(CancelEventArgs e)
|
protected override void OnClosing(CancelEventArgs e)
|
||||||
@@ -83,6 +104,8 @@ namespace Torch.Server
|
|||||||
|
|
||||||
if (_server?.State == ServerState.Running)
|
if (_server?.State == ServerState.Running)
|
||||||
_server.Stop();
|
_server.Stop();
|
||||||
|
|
||||||
|
Process.GetCurrentProcess().Kill();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void BtnRestart_Click(object sender, RoutedEventArgs e)
|
private void BtnRestart_Click(object sender, RoutedEventArgs e)
|
||||||
@@ -98,7 +121,7 @@ namespace Torch.Server
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
_config.InstancePath = name;
|
_config.InstancePath = name;
|
||||||
_server.GetManager<InstanceManager>().LoadInstance(_config.InstancePath);
|
_server.Managers.GetManager<InstanceManager>().LoadInstance(_config.InstancePath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,32 @@
|
|||||||
|
using System;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
|
||||||
|
namespace Torch.Server.Views.ValidationRules
|
||||||
|
{
|
||||||
|
public class ListConverterValidationRule : ValidationRule
|
||||||
|
{
|
||||||
|
public Type Type { get; set; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override ValidationResult Validate(object value, CultureInfo cultureInfo)
|
||||||
|
{
|
||||||
|
var converter = TypeDescriptor.GetConverter(Type);
|
||||||
|
var input = ((string)value).Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
foreach (var item in input)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
converter.ConvertFromString(item);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return new ValidationResult(false, $"{item} is not a valid value.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ValidationResult.ValidResult;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
22
Torch.Server/Views/ValidationRules/NumberValidationRule.cs
Normal file
22
Torch.Server/Views/ValidationRules/NumberValidationRule.cs
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
|
||||||
|
namespace Torch.Server.Views.ValidationRules
|
||||||
|
{
|
||||||
|
public class NumberValidationRule : ValidationRule
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override ValidationResult Validate(object value, CultureInfo cultureInfo)
|
||||||
|
{
|
||||||
|
if (!float.TryParse(value?.ToString(), out _))
|
||||||
|
return new ValidationResult(false, "Not a number.");
|
||||||
|
|
||||||
|
return ValidationResult.ValidResult;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
44
Torch.Server/Views/WorldGeneratorDialog.xaml
Normal file
44
Torch.Server/Views/WorldGeneratorDialog.xaml
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
<Window x:Class="Torch.Server.WorldGeneratorDialog"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:local="clr-namespace:Torch.Server"
|
||||||
|
xmlns:views="clr-namespace:Torch.Server.Views"
|
||||||
|
xmlns:views1="clr-namespace:Torch.Views;assembly=Torch"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
Title="WorldGeneratorDialog" Height="500" Width="700">
|
||||||
|
<Grid>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="250"/>
|
||||||
|
<ColumnDefinition Width="*"/>
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<ListView Grid.Column="0" x:Name="PremadeCheckpoints" ScrollViewer.CanContentScroll="False" HorizontalContentAlignment="Center" Margin="3" SelectionChanged="PremadeCheckpoints_SelectionChanged">
|
||||||
|
<ListView.ItemTemplate>
|
||||||
|
<DataTemplate DataType="local:PremadeCheckpointItem">
|
||||||
|
<StackPanel HorizontalAlignment="Center">
|
||||||
|
<Label Content="{Binding Name}" HorizontalAlignment="Center"/>
|
||||||
|
<Image Stretch="Uniform" MaxHeight="100" HorizontalAlignment="Center">
|
||||||
|
<Image.Source>
|
||||||
|
<BitmapImage UriSource="{Binding Icon}"/>
|
||||||
|
</Image.Source>
|
||||||
|
</Image>
|
||||||
|
</StackPanel>
|
||||||
|
</DataTemplate>
|
||||||
|
</ListView.ItemTemplate>
|
||||||
|
</ListView>
|
||||||
|
<Grid Grid.Column="1" Margin="3">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height ="Auto"/>
|
||||||
|
<RowDefinition Height ="*"/>
|
||||||
|
<RowDefinition Height ="Auto"/>
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<Label Content="World Name: "/>
|
||||||
|
<TextBox x:Name="WorldName" Width="300" Margin="3"/>
|
||||||
|
</StackPanel>
|
||||||
|
<views1:PropertyGrid Grid.Row="1" x:Name="SettingsView" Margin="3"/>
|
||||||
|
<Button Grid.Row="2" Content="Create World" Click="ButtonBase_OnClick" Margin ="3"/>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Window>
|
116
Torch.Server/Views/WorldGeneratorDialog.xaml.cs
Normal file
116
Torch.Server/Views/WorldGeneratorDialog.xaml.cs
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
using System.Windows.Data;
|
||||||
|
using System.Windows.Documents;
|
||||||
|
using System.Windows.Input;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using System.Windows.Media.Imaging;
|
||||||
|
using NLog;
|
||||||
|
using Sandbox.Definitions;
|
||||||
|
using Sandbox.Engine.Networking;
|
||||||
|
using Sandbox.Game.World;
|
||||||
|
using Torch.Server.Managers;
|
||||||
|
using Torch.Server.ViewModels;
|
||||||
|
using Torch.Utils;
|
||||||
|
using VRage;
|
||||||
|
using VRage.Dedicated;
|
||||||
|
using VRage.FileSystem;
|
||||||
|
using VRage.Game;
|
||||||
|
using VRage.Game.Localization;
|
||||||
|
using VRage.Utils;
|
||||||
|
|
||||||
|
namespace Torch.Server
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interaction logic for WorldGeneratorDialog.xaml
|
||||||
|
/// </summary>
|
||||||
|
public partial class WorldGeneratorDialog : Window
|
||||||
|
{
|
||||||
|
private InstanceManager _instanceManager;
|
||||||
|
private List<PremadeCheckpointItem> _checkpoints = new List<PremadeCheckpointItem>();
|
||||||
|
private PremadeCheckpointItem _currentItem;
|
||||||
|
|
||||||
|
[ReflectedStaticMethod(Type = typeof(ConfigForm), Name = "LoadLocalization")]
|
||||||
|
private static Action _loadLocalization;
|
||||||
|
|
||||||
|
public WorldGeneratorDialog(InstanceManager instanceManager)
|
||||||
|
{
|
||||||
|
_instanceManager = instanceManager;
|
||||||
|
InitializeComponent();
|
||||||
|
_loadLocalization();
|
||||||
|
var scenarios = MyLocalCache.GetAvailableWorldInfos(Path.Combine(MyFileSystem.ContentPath, "CustomWorlds"));
|
||||||
|
foreach (var tup in scenarios)
|
||||||
|
{
|
||||||
|
string directory = tup.Item1;
|
||||||
|
MyWorldInfo info = tup.Item2;
|
||||||
|
string localizedName = MyTexts.GetString(MyStringId.GetOrCompute(info.SessionName));
|
||||||
|
var checkpoint = MyLocalCache.LoadCheckpoint(directory, out _);
|
||||||
|
checkpoint.OnlineMode = MyOnlineModeEnum.PUBLIC;
|
||||||
|
_checkpoints.Add(new PremadeCheckpointItem { Name = localizedName, Icon = Path.Combine(directory, "thumb.jpg"), Path = directory, Checkpoint = checkpoint});
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
var premadeCheckpoints = Directory.EnumerateDirectories(Path.Combine("Content", "CustomWorlds"));
|
||||||
|
foreach (var path in premadeCheckpoints)
|
||||||
|
{
|
||||||
|
var thumbPath = Path.GetFullPath(Directory.EnumerateFiles(path).First(x => x.Contains("thumb")));
|
||||||
|
|
||||||
|
_checkpoints.Add(new PremadeCheckpointItem
|
||||||
|
{
|
||||||
|
Path = path,
|
||||||
|
Icon = thumbPath,
|
||||||
|
Name = Path.GetFileName(path)
|
||||||
|
});
|
||||||
|
}*/
|
||||||
|
PremadeCheckpoints.ItemsSource = _checkpoints;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
string worldName = string.IsNullOrEmpty(WorldName.Text) ? _currentItem.Name : WorldName.Text;
|
||||||
|
var worldPath = Path.Combine("Instance", "Saves", worldName);
|
||||||
|
var checkpoint= _currentItem.Checkpoint;
|
||||||
|
if (Directory.Exists(worldPath))
|
||||||
|
{
|
||||||
|
MessageBox.Show("World already exists with that name.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Directory.CreateDirectory(worldPath);
|
||||||
|
foreach (var file in Directory.EnumerateFiles(_currentItem.Path, "*", SearchOption.AllDirectories))
|
||||||
|
{
|
||||||
|
File.Copy(file, Path.Combine(worldPath, file.Replace($"{_currentItem.Path}\\", "")));
|
||||||
|
}
|
||||||
|
|
||||||
|
checkpoint.SessionName = worldName;
|
||||||
|
|
||||||
|
MyLocalCache.SaveCheckpoint(checkpoint, worldPath);
|
||||||
|
|
||||||
|
|
||||||
|
_instanceManager.SelectWorld(worldPath, false);
|
||||||
|
_instanceManager.LoadInstance(worldPath);
|
||||||
|
_instanceManager.ImportSelectedWorldConfig();
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PremadeCheckpoints_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||||
|
{
|
||||||
|
var selected = (PremadeCheckpointItem)PremadeCheckpoints.SelectedItem;
|
||||||
|
_currentItem = selected;
|
||||||
|
SettingsView.DataContext = new SessionSettingsViewModel(_currentItem.Checkpoint.Settings);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class PremadeCheckpointItem
|
||||||
|
{
|
||||||
|
public string Path { get; set; }
|
||||||
|
public string Name { get; set; }
|
||||||
|
public string Icon { get; set; }
|
||||||
|
public MyObjectBuilder_Checkpoint Checkpoint { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@@ -1,5 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<packages>
|
<packages>
|
||||||
|
<package id="ControlzEx" version="3.0.2.4" targetFramework="net461" />
|
||||||
|
<package id="MahApps.Metro" version="1.6.1" targetFramework="net461" />
|
||||||
<package id="Mono.TextTransform" version="1.0.0" targetFramework="net461" />
|
<package id="Mono.TextTransform" version="1.0.0" targetFramework="net461" />
|
||||||
<package id="Newtonsoft.Json" version="10.0.3" targetFramework="net461" />
|
<package id="Newtonsoft.Json" version="10.0.3" targetFramework="net461" />
|
||||||
<package id="NLog" version="4.4.12" targetFramework="net461" />
|
<package id="NLog" version="4.4.12" targetFramework="net461" />
|
||||||
|
@@ -1,10 +1,12 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Reflection.Emit;
|
using System.Reflection.Emit;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using Torch.Managers.PatchManager;
|
using Torch.Managers.PatchManager;
|
||||||
using Torch.Managers.PatchManager.MSIL;
|
using Torch.Managers.PatchManager.MSIL;
|
||||||
using Torch.Utils;
|
using Torch.Utils;
|
||||||
@@ -17,6 +19,7 @@ namespace Torch.Tests
|
|||||||
public class PatchTest
|
public class PatchTest
|
||||||
{
|
{
|
||||||
#region TestRunner
|
#region TestRunner
|
||||||
|
|
||||||
private static readonly PatchManager _patchContext = new PatchManager(null);
|
private static readonly PatchManager _patchContext = new PatchManager(null);
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
@@ -48,6 +51,133 @@ namespace Torch.Tests
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void TestTryCatchNop()
|
||||||
|
{
|
||||||
|
var ctx = _patchContext.AcquireContext();
|
||||||
|
ctx.GetPattern(TryCatchTest._target).Transpilers.Add(_nopTranspiler);
|
||||||
|
_patchContext.Commit();
|
||||||
|
Assert.False(TryCatchTest.Target());
|
||||||
|
Assert.True(TryCatchTest.FinallyHit);
|
||||||
|
_patchContext.FreeContext(ctx);
|
||||||
|
_patchContext.Commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void TestTryCatchCancel()
|
||||||
|
{
|
||||||
|
var ctx = _patchContext.AcquireContext();
|
||||||
|
ctx.GetPattern(TryCatchTest._target).Transpilers.Add(TryCatchTest._removeThrowTranspiler);
|
||||||
|
ctx.GetPattern(TryCatchTest._target).DumpTarget = @"C:\tmp\dump.txt";
|
||||||
|
ctx.GetPattern(TryCatchTest._target).DumpMode = MethodRewritePattern.PrintModeEnum.Original | MethodRewritePattern.PrintModeEnum.Patched;
|
||||||
|
_patchContext.Commit();
|
||||||
|
Assert.True(TryCatchTest.Target());
|
||||||
|
Assert.True(TryCatchTest.FinallyHit);
|
||||||
|
_patchContext.FreeContext(ctx);
|
||||||
|
_patchContext.Commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static readonly MethodInfo _nopTranspiler = typeof(PatchTest).GetMethod(nameof(NopTranspiler), BindingFlags.Static | BindingFlags.NonPublic);
|
||||||
|
|
||||||
|
private static IEnumerable<MsilInstruction> NopTranspiler(IEnumerable<MsilInstruction> input)
|
||||||
|
{
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
|
||||||
|
private class TryCatchTest
|
||||||
|
{
|
||||||
|
public static readonly MethodInfo _removeThrowTranspiler =
|
||||||
|
typeof(TryCatchTest).GetMethod(nameof(RemoveThrowTranspiler), BindingFlags.Static | BindingFlags.NonPublic);
|
||||||
|
|
||||||
|
private static IEnumerable<MsilInstruction> RemoveThrowTranspiler(IEnumerable<MsilInstruction> input)
|
||||||
|
{
|
||||||
|
foreach (var i in input)
|
||||||
|
if (i.OpCode == OpCodes.Throw)
|
||||||
|
yield return i.CopyWith(OpCodes.Pop);
|
||||||
|
else
|
||||||
|
yield return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static readonly MethodInfo _target = typeof(TryCatchTest).GetMethod(nameof(Target), BindingFlags.Public | BindingFlags.Static);
|
||||||
|
|
||||||
|
public static bool FinallyHit = false;
|
||||||
|
|
||||||
|
public static bool Target()
|
||||||
|
{
|
||||||
|
FinallyHit = false;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// shim to prevent compiler optimization
|
||||||
|
if ("test".Length > "".Length)
|
||||||
|
throw new Exception();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (IOException ioe)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
FinallyHit = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void TestAsyncNop()
|
||||||
|
{
|
||||||
|
var candidates = new List<Type>();
|
||||||
|
var nestedTypes = typeof(PatchTest).GetNestedTypes(BindingFlags.NonPublic | BindingFlags.Static);
|
||||||
|
foreach (var nested in nestedTypes)
|
||||||
|
if (nested.Name.StartsWith("<" + nameof(TestAsyncMethod) + ">"))
|
||||||
|
{
|
||||||
|
var good = false;
|
||||||
|
foreach (var itf in nested.GetInterfaces())
|
||||||
|
if (itf.FullName == typeof(IAsyncStateMachine).FullName)
|
||||||
|
{
|
||||||
|
good = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (good)
|
||||||
|
candidates.Add(nested);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (candidates.Count != 1)
|
||||||
|
throw new Exception("Couldn't find async worker");
|
||||||
|
|
||||||
|
var method = candidates[0].GetMethod("MoveNext", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
|
||||||
|
if (method == null)
|
||||||
|
throw new Exception("Failed to find state machine move next instruction, cannot proceed");
|
||||||
|
|
||||||
|
var ctx = _patchContext.AcquireContext();
|
||||||
|
ctx.GetPattern(method).Transpilers.Add(_nopTranspiler);
|
||||||
|
ctx.GetPattern(method).DumpTarget = @"C:\tmp\dump.txt";
|
||||||
|
ctx.GetPattern(method).DumpMode = MethodRewritePattern.PrintModeEnum.Original | MethodRewritePattern.PrintModeEnum.Patched;
|
||||||
|
_patchContext.Commit();
|
||||||
|
|
||||||
|
Assert.Equal("TEST", TestAsyncMethod().Result);
|
||||||
|
_patchContext.FreeContext(ctx);
|
||||||
|
_patchContext.Commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<string> TestAsyncMethod()
|
||||||
|
{
|
||||||
|
var first = await Task.Run(() => "TE");
|
||||||
|
var last = await Task.Run(() => "ST");
|
||||||
|
return await Task.Run(() => first + last);
|
||||||
|
}
|
||||||
|
|
||||||
public class TestBootstrap
|
public class TestBootstrap
|
||||||
{
|
{
|
||||||
@@ -82,7 +212,7 @@ namespace Torch.Tests
|
|||||||
if (_targetAssert == null)
|
if (_targetAssert == null)
|
||||||
throw new Exception($"{t.FullName} must have a method named AssertNormal");
|
throw new Exception($"{t.FullName} must have a method named AssertNormal");
|
||||||
_instance = !_targetMethod.IsStatic ? Activator.CreateInstance(t) : null;
|
_instance = !_targetMethod.IsStatic ? Activator.CreateInstance(t) : null;
|
||||||
_targetParams = (object[])t.GetField("_targetParams", flags)?.GetValue(null) ?? new object[0];
|
_targetParams = (object[]) t.GetField("_targetParams", flags)?.GetValue(null) ?? new object[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Invoke(MethodBase i, params object[] args)
|
private void Invoke(MethodBase i, params object[] args)
|
||||||
@@ -185,10 +315,11 @@ namespace Torch.Tests
|
|||||||
_patchTest.Add(new TestBootstrap(type));
|
_patchTest.Add(new TestBootstrap(type));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IEnumerable<object[]> Prefixes => _patchTest.Where(x => x.HasPrefix).Select(x => new object[] { x });
|
public static IEnumerable<object[]> Prefixes => _patchTest.Where(x => x.HasPrefix).Select(x => new object[] {x});
|
||||||
public static IEnumerable<object[]> Transpilers => _patchTest.Where(x => x.HasTranspile).Select(x => new object[] { x });
|
public static IEnumerable<object[]> Transpilers => _patchTest.Where(x => x.HasTranspile).Select(x => new object[] {x});
|
||||||
public static IEnumerable<object[]> Suffixes => _patchTest.Where(x => x.HasSuffix).Select(x => new object[] { x });
|
public static IEnumerable<object[]> Suffixes => _patchTest.Where(x => x.HasSuffix).Select(x => new object[] {x});
|
||||||
public static IEnumerable<object[]> Combo => _patchTest.Where(x => x.HasPrefix || x.HasTranspile || x.HasSuffix).Select(x => new object[] { x });
|
public static IEnumerable<object[]> Combo => _patchTest.Where(x => x.HasPrefix || x.HasTranspile || x.HasSuffix).Select(x => new object[] {x});
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region PatchTests
|
#region PatchTests
|
||||||
@@ -220,7 +351,8 @@ namespace Torch.Tests
|
|||||||
{
|
{
|
||||||
yield return new MsilInstruction(OpCodes.Ldnull);
|
yield return new MsilInstruction(OpCodes.Ldnull);
|
||||||
yield return new MsilInstruction(OpCodes.Ldc_I4_1);
|
yield return new MsilInstruction(OpCodes.Ldc_I4_1);
|
||||||
yield return new MsilInstruction(OpCodes.Stfld).InlineValue(typeof(StaticNoRetNoParm).GetField("_transpileHit", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public));
|
yield return new MsilInstruction(OpCodes.Stfld).InlineValue(typeof(StaticNoRetNoParm).GetField("_transpileHit",
|
||||||
|
BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public));
|
||||||
foreach (MsilInstruction i in instructions)
|
foreach (MsilInstruction i in instructions)
|
||||||
yield return i;
|
yield return i;
|
||||||
}
|
}
|
||||||
@@ -255,7 +387,7 @@ namespace Torch.Tests
|
|||||||
private class StaticNoRetParam
|
private class StaticNoRetParam
|
||||||
{
|
{
|
||||||
private static bool _prefixHit, _normalHit, _suffixHit;
|
private static bool _prefixHit, _normalHit, _suffixHit;
|
||||||
private static readonly object[] _targetParams = { "test", 1, new StringBuilder("test1") };
|
private static readonly object[] _targetParams = {"test", 1, new StringBuilder("test1")};
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||||
public static void Prefix(string str, int i, StringBuilder o)
|
public static void Prefix(string str, int i, StringBuilder o)
|
||||||
@@ -306,8 +438,8 @@ namespace Torch.Tests
|
|||||||
private class StaticNoRetParamReplace
|
private class StaticNoRetParamReplace
|
||||||
{
|
{
|
||||||
private static bool _prefixHit, _normalHit, _suffixHit;
|
private static bool _prefixHit, _normalHit, _suffixHit;
|
||||||
private static readonly object[] _targetParams = { "test", 1, new StringBuilder("stest1") };
|
private static readonly object[] _targetParams = {"test", 1, new StringBuilder("stest1")};
|
||||||
private static readonly object[] _replacedParams = { "test2", 2, new StringBuilder("stest2") };
|
private static readonly object[] _replacedParams = {"test2", 2, new StringBuilder("stest2")};
|
||||||
private static object[] _calledParams;
|
private static object[] _calledParams;
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||||
@@ -316,16 +448,16 @@ namespace Torch.Tests
|
|||||||
Assert.Equal(_targetParams[0], str);
|
Assert.Equal(_targetParams[0], str);
|
||||||
Assert.Equal(_targetParams[1], i);
|
Assert.Equal(_targetParams[1], i);
|
||||||
Assert.Equal(_targetParams[2], o);
|
Assert.Equal(_targetParams[2], o);
|
||||||
str = (string)_replacedParams[0];
|
str = (string) _replacedParams[0];
|
||||||
i = (int)_replacedParams[1];
|
i = (int) _replacedParams[1];
|
||||||
o = (StringBuilder)_replacedParams[2];
|
o = (StringBuilder) _replacedParams[2];
|
||||||
_prefixHit = true;
|
_prefixHit = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||||
public static void Target(string str, int i, StringBuilder o)
|
public static void Target(string str, int i, StringBuilder o)
|
||||||
{
|
{
|
||||||
_calledParams = new object[] { str, i, o };
|
_calledParams = new object[] {str, i, o};
|
||||||
_normalHit = true;
|
_normalHit = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -380,6 +512,7 @@ namespace Torch.Tests
|
|||||||
Assert.True(_prefixHit, "Failed to prefix");
|
Assert.True(_prefixHit, "Failed to prefix");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
#pragma warning restore 414
|
#pragma warning restore 414
|
||||||
|
@@ -86,6 +86,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Service Include="{508349B6-6B84-4DF5-91F0-309BEEBAD82D}" />
|
<Service Include="{508349B6-6B84-4DF5-91F0-309BEEBAD82D}" />
|
||||||
|
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
<Import Project="$(SolutionDir)\TransformOnBuild.targets" />
|
<Import Project="$(SolutionDir)\TransformOnBuild.targets" />
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user