(61d00a474) v0.9.7.1

This commit is contained in:
Regalis
2020-03-04 13:04:10 +01:00
parent 3c50efa5c9
commit 3c09ebe02f
5086 changed files with 786063 additions and 295871 deletions
@@ -1,35 +0,0 @@
#!/bin/bash
# MonoKickstart Shell Script
# Written by Ethan "flibitijibibo" Lee
# Move to script's directory
cd "`dirname "$0"`"
# Get the system architecture
UNAME=`uname`
ARCH=`uname -m`
# MonoKickstart picks the right libfolder, so just execute the right binary.
if [ "$UNAME" == "Darwin" ]; then
# ... Except on OSX.
export DYLD_LIBRARY_PATH=$DYLD_LIBRARY_PATH:./osx/
# El Capitan is a total idiot and wipes this variable out, making the
# Steam overlay disappear. This sidesteps "System Integrity Protection"
# and resets the variable with Valve's own variable (they provided this
# fix by the way, thanks Valve!). Note that you will need to update your
# launch configuration to the script location, NOT just the app location
# (i.e. Kick.app/Contents/MacOS/Kick, not just Kick.app).
# -flibit
if [ "$STEAM_DYLD_INSERT_LIBRARIES" != "" ] && [ "$DYLD_INSERT_LIBRARIES" == "" ]; then
export DYLD_INSERT_LIBRARIES="$STEAM_DYLD_INSERT_LIBRARIES"
fi
./DedicatedServer.bin.osx $@
else
if [ "$ARCH" == "x86_64" ]; then
./DedicatedServer.bin.x86_64 $@
else
./DedicatedServer.bin.x86 $@
fi
fi
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,134 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.0</TargetFramework>
<RootNamespace>Barotrauma</RootNamespace>
<Authors>FakeFish, Undertow Games</Authors>
<Product>Barotrauma Dedicated Server</Product>
<Version>0.9.7.0</Version>
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
<Platforms>AnyCPU;x64</Platforms>
<AssemblyName>DedicatedServer</AssemblyName>
<ApplicationIcon>..\BarotraumaShared\Icon.ico</ApplicationIcon>
<Configurations>Debug;Release;Unstable</Configurations>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DefineConstants>DEBUG;TRACE;SERVER;LINUX;USE_STEAM</DefineConstants>
<PlatformTarget>x64</PlatformTarget>
<OutputPath>..\bin\$(Configuration)Linux\</OutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<DefineConstants>TRACE;DEBUG;SERVER;LINUX;X64;USE_STEAM</DefineConstants>
<PlatformTarget>x64</PlatformTarget>
<OutputPath>..\bin\$(Configuration)Linux\</OutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<DefineConstants>TRACE;SERVER;LINUX;USE_STEAM</DefineConstants>
<PlatformTarget>x64</PlatformTarget>
<OutputPath>..\bin\$(Configuration)Linux\</OutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Unstable|AnyCPU'">
<DefineConstants>TRACE;SERVER;LINUX;USE_STEAM</DefineConstants>
<PlatformTarget>x64</PlatformTarget>
<OutputPath>..\bin\$(Configuration)Linux\</OutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<DefineConstants>TRACE;SERVER;LINUX;X64;USE_STEAM</DefineConstants>
<PlatformTarget>x64</PlatformTarget>
<OutputPath>..\bin\$(Configuration)Linux\</OutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Unstable|x64'">
<DefineConstants>TRACE;SERVER;LINUX;X64;USE_STEAM</DefineConstants>
<PlatformTarget>x64</PlatformTarget>
<OutputPath>..\bin\$(Configuration)Linux\</OutputPath>
</PropertyGroup>
<ItemGroup>
<Content Include="..\BarotraumaShared\**\*" CopyToOutputDirectory="PreserveNewest" />
<Content Remove="..\BarotraumaShared\**\*.cs" />
<Compile Include="..\BarotraumaShared\**\*.cs" />
</ItemGroup>
<ItemGroup Condition="'$(Configuration)'!='Debug'">
<ProjectReference Include="..\..\Libraries\Facepunch.Steamworks\Facepunch.Steamworks.Posix64.csproj" AdditionalProperties="Configuration=Release" />
<ProjectReference Include="..\..\Libraries\Farseer Physics Engine 3.5\Farseer.NetStandard.csproj" AdditionalProperties="Configuration=Release" />
<ProjectReference Include="..\..\Libraries\GameAnalytics\GA_SDK_NETSTANDARD\GA_SDK_NETSTANDARD.csproj" AdditionalProperties="Configuration=Release" />
<ProjectReference Include="..\..\Libraries\Hyper.ComponentModel\Hyper.ComponentModel.NetStandard.csproj" AdditionalProperties="Configuration=Release" />
<ProjectReference Include="..\..\Libraries\Lidgren.Network\Lidgren.NetStandard.csproj" AdditionalProperties="Configuration=Release" />
</ItemGroup>
<ItemGroup Condition="'$(Configuration)'=='Debug'">
<ProjectReference Include="..\..\Libraries\Facepunch.Steamworks\Facepunch.Steamworks.Posix64.csproj" AdditionalProperties="Configuration=Debug" />
<ProjectReference Include="..\..\Libraries\Farseer Physics Engine 3.5\Farseer.NetStandard.csproj" AdditionalProperties="Configuration=Debug" />
<ProjectReference Include="..\..\Libraries\GameAnalytics\GA_SDK_NETSTANDARD\GA_SDK_NETSTANDARD.csproj" AdditionalProperties="Configuration=Debug" />
<ProjectReference Include="..\..\Libraries\Hyper.ComponentModel\Hyper.ComponentModel.NetStandard.csproj" AdditionalProperties="Configuration=Debug" />
<ProjectReference Include="..\..\Libraries\Lidgren.Network\Lidgren.NetStandard.csproj" AdditionalProperties="Configuration=Debug" />
</ItemGroup>
<!-- Sourced from https://stackoverflow.com/a/45248069 -->
<Target Name="GetGitRevision" BeforeTargets="WriteGitRevision" Condition="'$(BuildHash)' == ''">
<PropertyGroup>
<!-- temp file for the git version (lives in "obj" folder)-->
<VerFile>$(IntermediateOutputPath)gitver</VerFile>
<BranchFile>$(IntermediateOutputPath)gitbranch</BranchFile>
</PropertyGroup>
<!-- write the hash to the temp file.-->
<Exec Command="git -C $(ProjectDir) rev-parse --short HEAD &gt; $(VerFile)" ContinueOnError="true">
<Output TaskParameter="exitcode" ItemName="exitcodes" />
</Exec>
<Exec Command="git -C $(ProjectDir) rev-parse --short HEAD --symbolic-full-name --abbrev-ref=strict &gt; $(BranchFile)" ContinueOnError="true" />
<Exec Command="echo GIT_UNAVAILABLE &gt; $(VerFile)" Condition="'%(exitcodes.identity)'&gt;0" />
<Exec Command="echo GIT_UNAVAILABLE &gt; $(BranchFile)" Condition="'%(exitcodes.identity)'&gt;0" />
<!-- read the version into the GitVersion itemGroup-->
<ReadLinesFromFile File="$(VerFile)">
<Output TaskParameter="Lines" ItemName="GitVersion" />
</ReadLinesFromFile>
<!-- Set the BuildHash property to contain the GitVersion, if it wasn't already set.-->
<PropertyGroup>
<BuildHash>@(GitVersion)</BuildHash>
</PropertyGroup>
<!-- read the branch into the GitBranch itemGroup-->
<ReadLinesFromFile File="$(BranchFile)">
<Output TaskParameter="Lines" ItemName="GitBranch" />
</ReadLinesFromFile>
<!-- Set the BuildHash property to contain the GitVersion, if it wasn't already set.-->
<PropertyGroup>
<BuildBranch>@(GitBranch)</BuildBranch>
</PropertyGroup>
</Target>
<Target Name="WriteGitRevision" BeforeTargets="CoreCompile">
<!-- names the obj/.../CustomAssemblyInfo.cs file -->
<PropertyGroup>
<CustomAssemblyInfoFile>$(IntermediateOutputPath)CustomAssemblyInfo.cs</CustomAssemblyInfoFile>
</PropertyGroup>
<!-- includes the CustomAssemblyInfo for compilation into your project -->
<ItemGroup>
<Compile Include="$(CustomAssemblyInfoFile)" />
</ItemGroup>
<!-- defines the AssemblyMetadata attribute that will be written -->
<ItemGroup>
<AssemblyAttributes Include="AssemblyMetadata">
<_Parameter1>GitRevision</_Parameter1>
<_Parameter2>$(BuildHash)</_Parameter2>
</AssemblyAttributes>
<AssemblyAttributes Include="AssemblyMetadata">
<_Parameter1>GitBranch</_Parameter1>
<_Parameter2>$(BuildBranch)</_Parameter2>
</AssemblyAttributes>
</ItemGroup>
<!-- writes the attribute to the customAssemblyInfo file -->
<WriteCodeFragment Language="C#" OutputFile="$(CustomAssemblyInfoFile)" AssemblyAttributes="@(AssemblyAttributes)" />
</Target>
</Project>
@@ -0,0 +1,147 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.0</TargetFramework>
<RootNamespace>Barotrauma</RootNamespace>
<Authors>FakeFish, Undertow Games</Authors>
<Product>Barotrauma Dedicated Server</Product>
<Version>0.9.7.0</Version>
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
<Platforms>AnyCPU;x64</Platforms>
<AssemblyName>DedicatedServer</AssemblyName>
<ApplicationIcon>..\BarotraumaShared\Icon.ico</ApplicationIcon>
<ReleaseVersion>0.9.0.0</ReleaseVersion>
<Configurations>Debug;Release;Unstable</Configurations>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DefineConstants>TRACE;SERVER;OSX;USE_STEAM;DEBUG;NETCOREAPP;NETCOREAPP3_0</DefineConstants>
<PlatformTarget>x64</PlatformTarget>
<OutputPath>..\bin\DebugMac</OutputPath>
<ConsolePause>true</ConsolePause>
<CheckForOverflowUnderflow></CheckForOverflowUnderflow>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<DefineConstants>TRACE;DEBUG;SERVER;OSX;X64;USE_STEAM</DefineConstants>
<PlatformTarget>x64</PlatformTarget>
<OutputPath>..\bin\$(Configuration)Mac\</OutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<DefineConstants>TRACE;SERVER;OSX;USE_STEAM;RELEASE;NETCOREAPP;NETCOREAPP3_0</DefineConstants>
<PlatformTarget>x64</PlatformTarget>
<DebugType></DebugType>
<OutputPath>..\bin\ReleaseMac</OutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Unstable|AnyCPU'">
<DefineConstants>TRACE;SERVER;OSX;USE_STEAM;RELEASE;NETCOREAPP;NETCOREAPP3_0;UNSTABLE</DefineConstants>
<PlatformTarget>x64</PlatformTarget>
<DebugType />
<OutputPath>..\bin\ReleaseMac</OutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<DefineConstants>TRACE;SERVER;OSX;X64;USE_STEAM</DefineConstants>
<PlatformTarget>x64</PlatformTarget>
<OutputPath>..\bin\$(Configuration)Mac\</OutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Unstable|x64'">
<DefineConstants>TRACE;SERVER;OSX;X64;USE_STEAM;UNSTABLE</DefineConstants>
<PlatformTarget>x64</PlatformTarget>
<OutputPath>..\bin\$(Configuration)Mac\</OutputPath>
</PropertyGroup>
<ItemGroup>
<Content Include="..\BarotraumaShared\**\*" CopyToOutputDirectory="PreserveNewest" />
<Content Remove="..\BarotraumaShared\**\*.cs" />
<Compile Include="..\BarotraumaShared\**\*.cs" />
<Content Remove="..\BarotraumaShared\libsteam_api64.dylib" />
<Content Remove="..\BarotraumaShared\libsteam_api64.so" />
</ItemGroup>
<ItemGroup Condition="'$(Configuration)'!='Debug'">
<ProjectReference Include="..\..\Libraries\Facepunch.Steamworks\Facepunch.Steamworks.Posix64.csproj" AdditionalProperties="Configuration=Release" />
<ProjectReference Include="..\..\Libraries\Farseer Physics Engine 3.5\Farseer.NetStandard.csproj" AdditionalProperties="Configuration=Release" />
<ProjectReference Include="..\..\Libraries\GameAnalytics\GA_SDK_NETSTANDARD\GA_SDK_NETSTANDARD.csproj" AdditionalProperties="Configuration=Release" />
<ProjectReference Include="..\..\Libraries\Hyper.ComponentModel\Hyper.ComponentModel.NetStandard.csproj" AdditionalProperties="Configuration=Release" />
<ProjectReference Include="..\..\Libraries\Lidgren.Network\Lidgren.NetStandard.csproj" AdditionalProperties="Configuration=Release" />
</ItemGroup>
<ItemGroup Condition="'$(Configuration)'=='Debug'">
<ProjectReference Include="..\..\Libraries\Facepunch.Steamworks\Facepunch.Steamworks.Posix64.csproj" AdditionalProperties="Configuration=Debug" />
<ProjectReference Include="..\..\Libraries\Farseer Physics Engine 3.5\Farseer.NetStandard.csproj" AdditionalProperties="Configuration=Debug" />
<ProjectReference Include="..\..\Libraries\GameAnalytics\GA_SDK_NETSTANDARD\GA_SDK_NETSTANDARD.csproj" AdditionalProperties="Configuration=Debug" />
<ProjectReference Include="..\..\Libraries\Hyper.ComponentModel\Hyper.ComponentModel.NetStandard.csproj" AdditionalProperties="Configuration=Debug" />
<ProjectReference Include="..\..\Libraries\Lidgren.Network\Lidgren.NetStandard.csproj" AdditionalProperties="Configuration=Debug" />
</ItemGroup>
<!-- Sourced from https://stackoverflow.com/a/45248069 -->
<ItemGroup>
<None Include="..\BarotraumaShared\libsteam_api64.dylib">
<Link>libsteam_api64.dylib</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
<Target Name="GetGitRevision" BeforeTargets="WriteGitRevision" Condition="'$(BuildHash)' == ''">
<PropertyGroup>
<!-- temp file for the git version (lives in "obj" folder)-->
<VerFile>$(IntermediateOutputPath)gitver</VerFile>
<BranchFile>$(IntermediateOutputPath)gitbranch</BranchFile>
</PropertyGroup>
<!-- write the hash to the temp file.-->
<Exec Command="git -C $(ProjectDir) rev-parse --short HEAD &gt; $(VerFile)" ContinueOnError="true">
<Output TaskParameter="exitcode" ItemName="exitcodes" />
</Exec>
<Exec Command="git -C $(ProjectDir) rev-parse --short HEAD --symbolic-full-name --abbrev-ref=strict &gt; $(BranchFile)" ContinueOnError="true" />
<Exec Command="echo GIT_UNAVAILABLE &gt; $(VerFile)" Condition="'%(exitcodes.identity)'&gt;0" />
<Exec Command="echo GIT_UNAVAILABLE &gt; $(BranchFile)" Condition="'%(exitcodes.identity)'&gt;0" />
<!-- read the version into the GitVersion itemGroup-->
<ReadLinesFromFile File="$(VerFile)">
<Output TaskParameter="Lines" ItemName="GitVersion" />
</ReadLinesFromFile>
<!-- Set the BuildHash property to contain the GitVersion, if it wasn't already set.-->
<PropertyGroup>
<BuildHash>@(GitVersion)</BuildHash>
</PropertyGroup>
<!-- read the branch into the GitBranch itemGroup-->
<ReadLinesFromFile File="$(BranchFile)">
<Output TaskParameter="Lines" ItemName="GitBranch" />
</ReadLinesFromFile>
<!-- Set the BuildHash property to contain the GitVersion, if it wasn't already set.-->
<PropertyGroup>
<BuildBranch>@(GitBranch)</BuildBranch>
</PropertyGroup>
</Target>
<Target Name="WriteGitRevision" BeforeTargets="CoreCompile">
<!-- names the obj/.../CustomAssemblyInfo.cs file -->
<PropertyGroup>
<CustomAssemblyInfoFile>$(IntermediateOutputPath)CustomAssemblyInfo.cs</CustomAssemblyInfoFile>
</PropertyGroup>
<!-- includes the CustomAssemblyInfo for compilation into your project -->
<ItemGroup>
<Compile Include="$(CustomAssemblyInfoFile)" />
</ItemGroup>
<!-- defines the AssemblyMetadata attribute that will be written -->
<ItemGroup>
<AssemblyAttributes Include="AssemblyMetadata">
<_Parameter1>GitRevision</_Parameter1>
<_Parameter2>$(BuildHash)</_Parameter2>
</AssemblyAttributes>
<AssemblyAttributes Include="AssemblyMetadata">
<_Parameter1>GitBranch</_Parameter1>
<_Parameter2>$(BuildBranch)</_Parameter2>
</AssemblyAttributes>
</ItemGroup>
<!-- writes the attribute to the customAssemblyInfo file -->
<WriteCodeFragment Language="C#" OutputFile="$(CustomAssemblyInfoFile)" AssemblyAttributes="@(AssemblyAttributes)" />
</Target>
</Project>
@@ -1,35 +0,0 @@
using System.Reflection;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Barotrauma Dedicated Server")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("")]
[assembly: AssemblyCopyright("Copyright © FakeFish 2018-2019")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("85232b20-074d-4723-b0c6-91495391e448")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("0.9.6.0")]
[assembly: AssemblyFileVersion("0.9.6.0")]
-322
View File
@@ -1,322 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">ReleaseLinux</Configuration>
<Platform Condition=" '$(Platform)' == '' ">x64</Platform>
<ProjectGuid>{85232B20-074D-4723-B0C6-91495391E448}</ProjectGuid>
<OutputType>Exe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Barotrauma</RootNamespace>
<AssemblyName>DedicatedServer</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<TargetFrameworkProfile />
<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>
<ReleaseVersion>0.9.0.0</ReleaseVersion>
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
</PropertyGroup>
<PropertyGroup>
<ApplicationIcon>..\BarotraumaShared\Icon.ico</ApplicationIcon>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'ReleaseLinux|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>..\bin\ReleaseLinux\</OutputPath>
<DefineConstants>TRACE;SERVER</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x64</PlatformTarget>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'DebugLinux|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>..\bin\DebugLinux\</OutputPath>
<DefineConstants>TRACE;SERVER;DEBUG</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'ReleaseMac|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>..\bin\ReleaseMac\</OutputPath>
<DefineConstants>TRACE;SERVER</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x64</PlatformTarget>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'DebugMac|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>..\bin\DebugMac\</OutputPath>
<DefineConstants>TRACE;SERVER;DEBUG</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'ReleaseWindows|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>..\bin\ReleaseWindows\</OutputPath>
<DefineConstants>TRACE;SERVER</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x64</PlatformTarget>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'DebugWindows|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>..\bin\DebugWindows\</OutputPath>
<DefineConstants>TRACE;SERVER;DEBUG</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'ReleaseLinux|x86'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x86\ReleaseLinux\</OutputPath>
<DefineConstants>TRACE;SERVER</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x86</PlatformTarget>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'DebugLinux|x86'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x86\DebugLinux\</OutputPath>
<DefineConstants>TRACE;SERVER;DEBUG</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x86</PlatformTarget>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'ReleaseMac|x86'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x86\ReleaseMac\</OutputPath>
<DefineConstants>TRACE;SERVER</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x86</PlatformTarget>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'DebugMac|x86'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x86\DebugMac\</OutputPath>
<DefineConstants>TRACE;SERVER;DEBUG</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x86</PlatformTarget>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'ReleaseWindows|x86'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x86\ReleaseWindows\</OutputPath>
<DefineConstants>TRACE;SERVER</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x86</PlatformTarget>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'DebugWindows|x86'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x86\DebugWindows\</OutputPath>
<DefineConstants>TRACE;SERVER;DEBUG</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x86</PlatformTarget>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<ItemGroup>
<Reference Include="GameAnalytics.Mono, Version=1.0.7018.15293, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\Libraries\NuGet\GameAnalytics.Mono.SDK.2.1.6\lib\net45\GameAnalytics.Mono.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Data.SQLite, Version=1.0.102.0, Culture=neutral, PublicKeyToken=db937bc2d44ff139, processorArchitecture=MSIL">
<HintPath>..\..\Libraries\NuGet\GameAnalytics.Mono.SDK.2.1.6\lib\net45\System.Data.SQLite.dll</HintPath>
</Reference>
<Reference Include="System.Xml" />
<Reference Include="System.Xml.Linq" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Configuration" />
<Reference Include="System.Core" />
<Reference Include="System.Data" />
<Reference Include="System.IO.Compression" />
<Reference Include="System.Runtime.Serialization" />
<Reference Include="System.ServiceModel" />
<Reference Include="System.Transactions" />
<Reference Include="NLog">
<HintPath>..\..\Libraries\NuGet\NLog.4.3.8\lib\net45\NLog.dll</HintPath>
</Reference>
<Reference Include="RestSharp">
<HintPath>..\..\Libraries\NuGet\RestSharp.105.2.3\lib\net45\RestSharp.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Source\Camera.cs" />
<Compile Include="Source\Characters\Character.cs" />
<Compile Include="Source\Characters\CharacterInfo.cs" />
<Compile Include="Source\Characters\CharacterNetworking.cs" />
<Compile Include="Source\DebugConsole.cs" />
<Compile Include="Source\Events\Missions\CombatMission.cs" />
<Compile Include="Source\Events\Missions\Mission.cs" />
<Compile Include="Source\GameMain.cs" />
<Compile Include="Source\GameSession\CrewManager.cs" />
<Compile Include="Source\GameSession\GameModes\CampaignMode.cs" />
<Compile Include="Source\GameSession\GameModes\CharacterCampaignData.cs" />
<Compile Include="Source\GameSession\GameModes\MissionMode.cs" />
<Compile Include="Source\GameSession\GameModes\MultiPlayerCampaign.cs" />
<Compile Include="Source\Items\Components\Door.cs" />
<Compile Include="Source\Items\Components\ItemComponent.cs" />
<Compile Include="Source\Items\Components\ItemLabel.cs" />
<Compile Include="Source\Items\Components\Machines\Controller.cs" />
<Compile Include="Source\Items\Components\Machines\Deconstructor.cs" />
<Compile Include="Source\Items\Components\Machines\Engine.cs" />
<Compile Include="Source\Items\Components\Machines\Fabricator.cs" />
<Compile Include="Source\Items\Components\Machines\Pump.cs" />
<Compile Include="Source\Items\Components\Machines\Reactor.cs" />
<Compile Include="Source\Items\Components\Machines\Steering.cs" />
<Compile Include="Source\Items\Components\Power\PowerContainer.cs" />
<Compile Include="Source\Items\Components\Repairable.cs" />
<Compile Include="Source\Items\Components\Signal\ConnectionPanel.cs" />
<Compile Include="Source\Items\Components\Signal\CustomInterface.cs" />
<Compile Include="Source\Items\Components\Signal\Wire.cs" />
<Compile Include="Source\Items\Inventory.cs" />
<Compile Include="Source\Items\Item.cs" />
<Compile Include="Source\Map\Hull.cs" />
<Compile Include="Source\Map\Structure.cs" />
<Compile Include="Source\Map\Submarine.cs" />
<Compile Include="Source\Networking\BanList.cs" />
<Compile Include="Source\Networking\ChatMessage.cs" />
<Compile Include="Source\Networking\Client.cs" />
<Compile Include="Source\Networking\EntitySpawner.cs" />
<Compile Include="Source\Networking\FileTransfer\FileSender.cs" />
<Compile Include="Source\Networking\GameServer.cs" />
<Compile Include="Source\Networking\KarmaManager.cs" />
<Compile Include="Source\Networking\NetEntityEvent\ServerEntityEventManager.cs" />
<Compile Include="Source\Networking\NetworkMember.cs" />
<Compile Include="Source\Networking\OrderChatMessage.cs" />
<Compile Include="Source\Networking\Primitives\Peers\Server\LidgrenServerPeer.cs" />
<Compile Include="Source\Networking\Primitives\Peers\Server\ServerPeer.cs" />
<Compile Include="Source\Networking\Primitives\Peers\Server\SteamP2PServerPeer.cs" />
<Compile Include="Source\Networking\RespawnManager.cs" />
<Compile Include="Source\Networking\ServerSettings.cs" />
<Compile Include="Source\Networking\SteamManager.cs" />
<Compile Include="Source\Networking\Voip\VoipServer.cs" />
<Compile Include="Source\Networking\Voting.cs" />
<Compile Include="Source\Networking\WhiteList.cs" />
<Compile Include="Source\Physics\PhysicsBody.cs" />
<Compile Include="Source\PlayerInput.cs" />
<Compile Include="Source\Program.cs" />
<Compile Include="Source\Screens\NetLobbyScreen.cs" />
<Compile Include="Source\Screens\UnimplementedScreen.cs" />
<Compile Include="Source\Traitors\Goals\GoalInjectTarget.cs" />
<Compile Include="Source\Traitors\Goals\GoalEntityTransformation.cs" />
<Compile Include="Source\Traitors\Goals\GoalKeepTransformedAlive.cs" />
<Compile Include="Source\Traitors\Goals\GoalUnwiring.cs" />
<Compile Include="Source\Traitors\Goals\GoalWaitForTraitors.cs" />
<Compile Include="Source\Traitors\Goals\HumanoidGoal.cs" />
<Compile Include="Source\Traitors\Goals\Modifiers\GoalIsOptional.cs" />
<Compile Include="Source\Traitors\Goals\Modifiers\Modifier.cs" />
<Compile Include="Source\Utils\MonogameTypes\Color.cs" />
<Compile Include="Source\Utils\MonogameTypes\Graphics\SpriteEffects.cs" />
<Compile Include="Source\Utils\MonogameTypes\Input\KeyboardState.cs" />
<Compile Include="Source\Utils\MonogameTypes\Input\Keys.cs" />
<Compile Include="Source\Utils\MonogameTypes\Input\KeyState.cs" />
<Compile Include="Source\Utils\MonogameTypes\Point.cs" />
<Compile Include="Source\Utils\MonogameTypes\Quaternion.cs" />
<Compile Include="Source\Utils\MonogameTypes\Rectangle.cs" />
<Compile Include="Source\Utils\MonogameTypes\Vector4.cs" />
<Compile Include="Source\Utils\XnaToConsoleColor.cs" />
<Compile Include="Source\Traitors\TraitorManager.cs" />
<Compile Include="Source\Traitors\TraitorMissionPrefab.cs" />
<Compile Include="Source\Traitors\Goals\Goal.cs" />
<Compile Include="Source\Traitors\Objective.cs" />
<Compile Include="Source\Traitors\TraitorMission.cs" />
<Compile Include="Source\Traitors\Goals\GoalKillTarget.cs" />
<Compile Include="Source\Traitors\Goals\Modifiers\GoalHasDuration.cs" />
<Compile Include="Source\Traitors\Goals\GoalSabotageItems.cs" />
<Compile Include="Source\Traitors\Goals\GoalDestroyItemsWithTag.cs" />
<Compile Include="Source\Traitors\Goals\GoalFloodPercentOfSub.cs" />
<Compile Include="Source\Traitors\Goals\GoalFindItem.cs" />
<Compile Include="Source\Traitors\Goals\GoalReplaceInventory.cs" />
<Compile Include="Source\Traitors\Traitor.cs" />
<Compile Include="Source\Traitors\Goals\Modifiers\GoalHasTimeLimit.cs" />
<Compile Include="Source\Traitors\Goals\GoalReachDistanceFromSub.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Libraries\Facepunch.Steamworks\Facepunch.Steamworks.csproj">
<Project>{3af0347c-5a9b-4421-868c-8ee3dbfaebc6}</Project>
<Name>Facepunch.Steamworks</Name>
</ProjectReference>
<ProjectReference Include="..\..\Libraries\Farseer Physics Engine 3.5\Farseer Physics.csproj">
<Project>{a4610e4c-dd34-428b-babb-779ca0b5993a}</Project>
<Name>Farseer Physics</Name>
</ProjectReference>
<ProjectReference Include="..\..\Libraries\Hyper.ComponentModel\Hyper.ComponentModel.csproj">
<Project>{3b8f9edb-6e5e-450c-abc2-ec49075d0b50}</Project>
<Name>Hyper.ComponentModel</Name>
</ProjectReference>
<ProjectReference Include="..\..\Libraries\Lidgren.Network\Lidgren.Network.csproj">
<Project>{49ba1c69-6104-41ac-a5d8-b54fa9f696e8}</Project>
<Name>Lidgren.Network</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<BootstrapperPackage Include=".NETFramework,Version=v4.5">
<Visible>False</Visible>
<ProductName>Microsoft .NET Framework 4.5 %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>
<ItemGroup>
<WCFMetadata Include="Service References\" />
</ItemGroup>
<ItemGroup Condition="$(Configuration.EndsWith('Linux')) Or $(Configuration.EndsWith('Mac'))">
<None Include="DedicatedServer">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="DedicatedServer.bin.x86">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="DedicatedServer.bin.x86_64">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="DedicatedServer.bin.osx">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="packages.config" />
</ItemGroup>
<ItemGroup />
<Import Project="..\BarotraumaShared\SharedCode.projitems" Label="Shared" />
<Import Project="..\BarotraumaShared\SharedContent.projitems" Label="Shared" />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="..\..\Libraries\NuGet\GameAnalytics.Mono.SDK.2.1.6\build\net45\GameAnalytics.Mono.SDK.targets" Condition="Exists('..\..\Libraries\NuGet\GameAnalytics.Mono.SDK.2.1.6\build\net45\GameAnalytics.Mono.SDK.targets')" />
</Project>
@@ -6,6 +6,8 @@ namespace Barotrauma
{
public class Camera
{
public static Camera Instance = new Camera();
public static bool FollowSub = true;
const float DefaultZoom = 1.0f;
@@ -169,43 +171,8 @@ namespace Barotrauma
}
public void MoveCamera(float deltaTime, bool allowMove = true, bool allowZoom = true)
{
prevPosition = position;
prevZoom = zoom;
float moveSpeed = 20.0f/zoom;
Vector2 moveCam = Vector2.Zero;
if (targetPos == Vector2.Zero)
{
}
else
{
Vector2 mousePos = PlayerInput.MousePosition;
Vector2 offset = mousePos - new Vector2(resolution.X / 2.0f, resolution.Y / 2.0f);
offset.X = offset.X / (resolution.X * 0.4f);
offset.Y = -offset.Y / (resolution.Y * 0.3f);
if (offset.Length() > 1.0f) offset.Normalize();
offset = offset * offsetAmount;
float newZoom = Math.Min(DefaultZoom - Math.Min(offset.Length() / resolution.Y, 1.0f),1.0f);
Zoom += (newZoom - zoom) / ZoomSmoothness;
Vector2 diff = (targetPos + offset) - position;
moveCam = diff / MoveSmoothness;
}
shakeTargetPosition = Rand.Vector(Shake);
shakePosition = Vector2.Lerp(shakePosition, shakeTargetPosition, 0.5f);
Shake = MathHelper.Lerp(Shake, 0.0f, deltaTime * 2.0f);
Translate(moveCam + shakePosition);
{
return;
}
public Vector2 Position
@@ -2,6 +2,7 @@
using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
using System.Linq;
namespace Barotrauma
{
@@ -87,7 +88,7 @@ namespace Barotrauma
memInput[memInput.Count - 1].states.HasFlag(InputNetFlags.Grab))
{
focusedItem = null;
focusedCharacter = null;
FocusedCharacter = null;
}
var closestEntity = FindEntityByID(memInput[memInput.Count - 1].interact);
if (closestEntity is Item)
@@ -95,14 +96,14 @@ namespace Barotrauma
if (CanInteractWith((Item)closestEntity))
{
focusedItem = (Item)closestEntity;
focusedCharacter = null;
FocusedCharacter = null;
}
}
else if (closestEntity is Character)
{
if (CanInteractWith((Character)closestEntity))
{
focusedCharacter = (Character)closestEntity;
FocusedCharacter = (Character)closestEntity;
focusedItem = null;
}
}
@@ -264,7 +265,8 @@ namespace Barotrauma
{
case NetEntityEvent.Type.InventoryState:
msg.WriteRangedInteger(0, 0, 3);
Inventory.SharedWrite(msg, extraData);
msg.Write(GameMain.Server.EntityEventManager.Events.Last()?.ID ?? (ushort)0);
Inventory.ServerWrite(msg, c);
break;
case NetEntityEvent.Type.Control:
msg.WriteRangedInteger(1, 0, 3);
@@ -337,7 +339,6 @@ namespace Barotrauma
use = keys[(int)InputType.Use].GetHeldQueue;
attack = keys[(int)InputType.Attack].GetHeldQueue;
shoot = keys[(int)InputType.Shoot].GetHeldQueue;
networkUpdateSent = true;
}
@@ -401,7 +402,7 @@ namespace Barotrauma
tempBuffer.WritePadBits();
msg.Write((byte)tempBuffer.LengthBytes);
msg.WriteVariableUInt32((uint)tempBuffer.LengthBytes);
msg.Write(tempBuffer.Buffer, 0, tempBuffer.LengthBytes);
}
}
@@ -414,7 +415,7 @@ namespace Barotrauma
msg.WriteRangedInteger((int)CauseOfDeath.Type, 0, Enum.GetValues(typeof(CauseOfDeathType)).Length - 1);
if (CauseOfDeath.Type == CauseOfDeathType.Affliction)
{
msg.WriteRangedInteger(AfflictionPrefab.List.IndexOf(CauseOfDeath.Affliction), 0, AfflictionPrefab.List.Count - 1);
msg.Write(CauseOfDeath.Affliction.Identifier);
}
if (AnimController?.LimbJoints == null)
@@ -445,7 +446,7 @@ namespace Barotrauma
}
}
public void WriteSpawnData(IWriteMessage msg, UInt16 entityId)
public void WriteSpawnData(IWriteMessage msg, UInt16 entityId, bool restrictMessageSize)
{
if (GameMain.Server == null) return;
@@ -472,7 +473,7 @@ namespace Barotrauma
//character with no characterinfo (e.g. some monster)
if (Info == null)
{
WriteStatus(msg);
TryWriteStatus(msg);
return;
}
@@ -496,7 +497,48 @@ namespace Barotrauma
msg.Write(this is AICharacter);
msg.Write(info.SpeciesName);
info.ServerWrite(msg);
WriteStatus(msg);
// Current order
if (info.CurrentOrder != null)
{
msg.Write(true);
msg.Write((byte)Order.PrefabList.IndexOf(info.CurrentOrder.Prefab));
msg.Write(info.CurrentOrder.TargetEntity == null ? (UInt16)0 :
info.CurrentOrder.TargetEntity.ID);
if (info.CurrentOrder.OrderGiver != null)
{
msg.Write(true);
msg.Write(info.CurrentOrder.OrderGiver.ID);
}
else
{
msg.Write(false);
}
msg.Write((byte)(string.IsNullOrWhiteSpace(info.CurrentOrderOption) ? 0 :
Array.IndexOf(info.CurrentOrder.Prefab.Options, info.CurrentOrderOption)));
}
else
{
msg.Write(false);
}
TryWriteStatus(msg);
void TryWriteStatus(IWriteMessage msg)
{
var tempBuffer = new ReadWriteMessage();
WriteStatus(tempBuffer);
if (msg.LengthBytes + tempBuffer.LengthBytes >= 255 && restrictMessageSize)
{
msg.Write(false);
DebugConsole.ThrowError($"Error when writing character spawn data: status data caused the length of the message to exceed 255 bytes ({msg.LengthBytes} + {tempBuffer.LengthBytes})");
}
else
{
msg.Write(true);
WriteStatus(msg);
}
}
DebugConsole.Log("Character spawn message length: " + (msg.LengthBytes - msgLength));
}
@@ -9,6 +9,7 @@ using Barotrauma.Items.Components;
using System.Threading;
using System.IO;
using System.Text;
using System.Diagnostics;
namespace Barotrauma
{
@@ -28,12 +29,10 @@ namespace Barotrauma
NewMessage("Client \"" + client.Name + "\" attempted to use the command \"" + names[0] + "\". Cheats must be enabled using \"enablecheats\" before the command can be used.", Color.Red);
GameMain.Server.SendConsoleMessage("You need to enable cheats using the command \"enablecheats\" before you can use the command \"" + names[0] + "\".", client);
if (Steam.SteamManager.USE_STEAM)
{
NewMessage("Enabling cheats will disable Steam achievements during this play session.", Color.Red);
GameMain.Server.SendConsoleMessage("Enabling cheats will disable Steam achievements during this play session.", client);
return;
}
#if USE_STEAM
NewMessage("Enabling cheats will disable Steam achievements during this play session.", Color.Red);
GameMain.Server.SendConsoleMessage("Enabling cheats will disable Steam achievements during this play session.", client);
#endif
return;
}
@@ -51,7 +50,6 @@ namespace Barotrauma
}
public static List<string> QueuedCommands = new List<string>();
public static Thread InputThread;
public static void Update()
{
@@ -63,13 +61,35 @@ namespace Barotrauma
QueuedCommands.RemoveAt(0);
}
}
if (InputThread == null)
}
private static string input = "";
private static int memoryIndex = -1;
private static List<string> commandMemory = new List<string>();
public static void UpdateCommandLine(int maxTime)
{
Stopwatch sw = new Stopwatch();
sw.Start();
int consoleWidth = Console.WindowWidth;
if (consoleWidth < 5) consoleWidth = 5;
int consoleHeight = Console.WindowHeight;
if (consoleHeight < 5) consoleHeight = 5;
//dequeue messages
lock (queuedMessages)
{
lock (queuedMessages)
if (queuedMessages.Count > 0)
{
int inputLines = Math.Max((int)Math.Ceiling(input.Length / (float)Console.WindowWidth), 1);
Console.CursorLeft = 0;
Console.Write(new string(' ', consoleWidth));
Console.CursorTop = Math.Max(Console.CursorTop - inputLines, 0);
Console.CursorLeft = 0;
while (queuedMessages.Count > 0)
{
var msg = queuedMessages.Dequeue();
ColoredText msg = queuedMessages.Dequeue();
Messages.Add(msg);
if (GameSettings.SaveDebugConsoleLogs)
{
@@ -80,175 +100,96 @@ namespace Barotrauma
unsavedMessages.Clear();
}
}
string msgTxt = msg.Text;
if (msg.IsCommand) commandMemory.Add(msgTxt);
int paddingLen = consoleWidth - (msg.Text.Length % consoleWidth)-1;
msgTxt += new string(' ', paddingLen>0 ? paddingLen : 0);
Console.ForegroundColor = XnaToConsoleColor.Convert(msg.Color);
Console.WriteLine(msgTxt);
if (sw.ElapsedMilliseconds >= maxTime) { break; }
}
if (Messages.Count > MaxMessages)
{
Messages.RemoveRange(0, Messages.Count - MaxMessages);
}
RewriteInputToCommandLine(input);
}
}
}
public static void UpdateCommandLine()
{
try
{
Console.Clear();
string input = "";
int memoryIndex = -1;
List<string> commandMemory = new List<string>();
while (true)
if (Messages.Count > MaxMessages)
{
int consoleWidth = Console.WindowWidth;
if (consoleWidth < 5) consoleWidth = 5;
int consoleHeight = Console.WindowHeight;
if (consoleHeight < 5) consoleHeight = 5;
//dequeue messages
lock (queuedMessages)
{
if (queuedMessages.Count > 0)
{
int inputLines = Math.Max((int)Math.Ceiling(input.Length / (float)Console.WindowWidth), 1);
Console.CursorLeft = 0;
Console.Write(new string(' ', consoleWidth));
Console.CursorTop = Math.Max(Console.CursorTop - inputLines, 0);
Console.CursorLeft = 0;
while (queuedMessages.Count > 0)
{
ColoredText msg = queuedMessages.Dequeue();
Messages.Add(msg);
if (GameSettings.SaveDebugConsoleLogs)
{
unsavedMessages.Add(msg);
if (unsavedMessages.Count >= messagesPerFile)
{
SaveLogs();
unsavedMessages.Clear();
}
}
string msgTxt = msg.Text;
if (msg.IsCommand) commandMemory.Add(msgTxt);
int paddingLen = consoleWidth - (msg.Text.Length % consoleWidth)-1;
msgTxt += new string(' ', paddingLen>0 ? paddingLen : 0);
Console.ForegroundColor = XnaToConsoleColor.Convert(msg.Color);
Console.WriteLine(msgTxt);
}
RewriteInputToCommandLine(input);
}
if (Messages.Count > MaxMessages)
{
Messages.RemoveRange(0, Messages.Count - MaxMessages);
}
}
//read player input
if (Console.KeyAvailable)
{
ConsoleKeyInfo key = Console.ReadKey(true);
switch (key.Key)
{
case ConsoleKey.Enter:
lock (QueuedCommands)
{
QueuedCommands.Add(input);
}
input = "";
memoryIndex = -1;
break;
case ConsoleKey.Backspace:
if (input.Length > 0) input = input.Substring(0, input.Length - 1);
memoryIndex = -1;
break;
case ConsoleKey.LeftArrow:
input = AutoComplete(input, -1);
break;
case ConsoleKey.RightArrow:
input = AutoComplete(input, 1);
break;
case ConsoleKey.UpArrow:
memoryIndex--;
if (memoryIndex < 0) memoryIndex = commandMemory.Count - 1;
if (memoryIndex >= commandMemory.Count) memoryIndex = commandMemory.Count - 1;
if (memoryIndex >= 0)
{
input = commandMemory[memoryIndex];
}
break;
case ConsoleKey.DownArrow:
memoryIndex++;
if (memoryIndex < 0) memoryIndex = 0;
if (memoryIndex >= commandMemory.Count) memoryIndex = 0;
if (commandMemory.Count>0)
{
input = commandMemory[memoryIndex];
}
break;
case ConsoleKey.Tab:
if (input.Length > 0)
{
input = AutoComplete(input, 0);
memoryIndex = -1;
}
break;
default:
if (key.Modifiers.HasFlag(ConsoleModifiers.Control))
{
if (key.Key == ConsoleKey.Z)
{
activeQuestionCallback = null;
NewMessage("^Z");
}
else if (key.Key == ConsoleKey.D)
{
activeQuestionCallback = null;
NewMessage("^D");
}
}
else if (key.KeyChar != 0)
{
input += key.KeyChar;
memoryIndex = -1;
}
ResetAutoComplete();
break;
}
RewriteInputToCommandLine(input);
}
//TODO: be more clever about it
Thread.Sleep(10); //sleep for 10ms to not pin the CPU super hard
Messages.RemoveRange(0, Messages.Count - MaxMessages);
}
}
catch (ThreadAbortException)
//read player input
bool rewriteInput = false;
while (Console.KeyAvailable)
{
//don't have anything to do here yet
if (sw.ElapsedMilliseconds >= maxTime)
{
rewriteInput = false;
break;
}
rewriteInput = true;
ConsoleKeyInfo key = Console.ReadKey(true);
switch (key.Key)
{
case ConsoleKey.Enter:
lock (QueuedCommands)
{
QueuedCommands.Add(input);
}
input = "";
memoryIndex = -1;
break;
case ConsoleKey.Backspace:
if (input.Length > 0) input = input.Substring(0, input.Length - 1);
memoryIndex = -1;
break;
case ConsoleKey.LeftArrow:
input = AutoComplete(input, -1);
break;
case ConsoleKey.RightArrow:
input = AutoComplete(input, 1);
break;
case ConsoleKey.UpArrow:
memoryIndex--;
if (memoryIndex < 0) memoryIndex = commandMemory.Count - 1;
if (memoryIndex >= commandMemory.Count) memoryIndex = commandMemory.Count - 1;
if (memoryIndex >= 0)
{
input = commandMemory[memoryIndex];
}
break;
case ConsoleKey.DownArrow:
memoryIndex++;
if (memoryIndex < 0) memoryIndex = 0;
if (memoryIndex >= commandMemory.Count) memoryIndex = 0;
if (commandMemory.Count>0)
{
input = commandMemory[memoryIndex];
}
break;
case ConsoleKey.Tab:
if (input.Length > 0)
{
input = AutoComplete(input, 0);
memoryIndex = -1;
}
break;
default:
if (key.KeyChar != 0)
{
input += key.KeyChar;
memoryIndex = -1;
}
ResetAutoComplete();
break;
}
}
#if !DEBUG
catch (Exception exception)
{
StreamWriter sw = new StreamWriter("inputthreadcrash.log");
if (rewriteInput) { RewriteInputToCommandLine(input); }
StringBuilder sb = new StringBuilder();
sb.AppendLine("Barotrauma Dedicated Server input thread crash report (generated on " + DateTime.Now + ")");
sb.AppendLine("\n");
sb.AppendLine("Exception: " + exception.Message);
sb.AppendLine("Target site: " + exception.TargetSite.ToString());
sb.AppendLine("Stack trace: ");
sb.AppendLine(exception.StackTrace);
sw.WriteLine(sb.ToString());
sw.Close();
GameMain.ShouldRun = false;
}
#endif
sw.Stop();
}
private static void RewriteInputToCommandLine(string input)
@@ -282,6 +223,43 @@ namespace Barotrauma
}
}
public static void Clear()
{
lock (queuedMessages)
{
while (queuedMessages.Count > 0)
{
var msg = queuedMessages.Dequeue();
Messages.Add(msg);
if (GameSettings.SaveDebugConsoleLogs)
{
unsavedMessages.Add(msg);
if (unsavedMessages.Count >= messagesPerFile)
{
SaveLogs();
unsavedMessages.Clear();
}
}
}
if (Messages.Count > MaxMessages)
{
Messages.RemoveRange(0, Messages.Count - MaxMessages);
}
}
}
private static Client FindClient(string arg)
{
Client client = GameMain.Server.ConnectedClients.Find(c => Homoglyphs.Compare(c.Name, arg));
if (int.TryParse(arg, out int id))
{
client ??= GameMain.Server.ConnectedClients.Find(c => c.ID == id);
}
client ??= GameMain.Server.ConnectedClients.Find(c => c.EndpointMatches(arg));
client ??= GameMain.Server.ConnectedClients.Find(c => c.SteamID == Steam.SteamManager.SteamIDStringToUInt64(arg));
return client;
}
private static void AssignOnClientRequestExecute(string names, Action<Client, Vector2, string[]> onClientRequestExecute)
{
var matchingCommand = commands.Find(c => c.names.Intersect(names.Split('|')).Count() > 0);
@@ -305,6 +283,15 @@ namespace Barotrauma
GameMain.NetLobbyScreen.SetBotCount(botCount);
NewMessage("Set the number of bots to " + botCount, Color.White);
});
AssignOnClientRequestExecute("botcount", (Client client, Vector2 cursorPos, string[] args) =>
{
if (args.Length < 1 || GameMain.Server == null) return;
int botCount = GameMain.Server.ServerSettings.BotCount;
int.TryParse(args[0], out botCount);
GameMain.NetLobbyScreen.SetBotCount(botCount);
NewMessage(client.Name + " set the number of bots to " + botCount, Color.White);
GameMain.Server.SendConsoleMessage("Set the number of bots to " + botCount, client);
});
AssignOnExecute("botspawnmode", (string[] args) =>
{
@@ -319,6 +306,50 @@ namespace Barotrauma
NewMessage("\"" + args[0] + "\" is not a valid bot spawn mode. (Valid modes are Fill and Normal)", Color.White);
}
});
AssignOnClientRequestExecute("botspawnmode", (Client client, Vector2 cursorPos, string[] args) =>
{
if (args.Length < 1 || GameMain.Server == null) return;
if (Enum.TryParse(args[0], true, out BotSpawnMode spawnMode))
{
GameMain.NetLobbyScreen.SetBotSpawnMode(spawnMode);
NewMessage(client.Name + " set bot spawn mode to " + spawnMode, Color.White);
GameMain.Server.SendConsoleMessage("Set bot spawn mode to " + spawnMode, client);
}
else
{
GameMain.Server.SendConsoleMessage("\"" + args[0] + "\" is not a valid bot spawn mode. (Valid modes are Fill and Normal)", client);
}
});
AssignOnExecute("killdisconnectedtimer", (string[] args) =>
{
if (args.Length < 1 || GameMain.Server == null) return;
float seconds = GameMain.Server.ServerSettings.KillDisconnectedTime;
if (float.TryParse(args[0], out seconds))
{
seconds = Math.Max(0, seconds);
NewMessage("Set kill disconnected timer to " + ToolBox.SecondsToReadableTime(seconds), Color.White);
}
else
{
NewMessage("\"" + args[0] + "\" is not a valid duration.", Color.White);
}
});
AssignOnClientRequestExecute("killdisconnectedtimer", (Client client, Vector2 cursorPos, string[] args) =>
{
if (args.Length < 1 || GameMain.Server == null) return;
float seconds = GameMain.Server.ServerSettings.KillDisconnectedTime;
if (float.TryParse(args[0], out seconds))
{
seconds = Math.Max(0, seconds);
GameMain.Server.SendConsoleMessage("Set kill disconnected timer to " + ToolBox.SecondsToReadableTime(seconds), client);
NewMessage(client.Name + " set kill disconnected timer to " + ToolBox.SecondsToReadableTime(seconds), Color.White);
}
else
{
GameMain.Server.SendConsoleMessage("\"" + args[0] + "\" is not a valid duration.", client);
}
});
AssignOnExecute("autorestart", (string[] args) =>
{
@@ -337,10 +368,6 @@ namespace Barotrauma
if (GameMain.Server.ServerSettings.AutoRestartInterval <= 0) GameMain.Server.ServerSettings.AutoRestartInterval = 10;
GameMain.Server.ServerSettings.AutoRestartTimer = GameMain.Server.ServerSettings.AutoRestartInterval;
GameMain.Server.ServerSettings.AutoRestart = enabled;
#if CLIENT
//TODO: reimplement
GameMain.NetLobbyScreen.SetAutoRestart(enabled, GameMain.Server.AutoRestartTimer);
#endif
GameMain.NetLobbyScreen.LastUpdateID++;
}
NewMessage(GameMain.Server.ServerSettings.AutoRestart ? "Automatic restart enabled." : "Automatic restart disabled.", Color.White);
@@ -365,10 +392,6 @@ namespace Barotrauma
GameMain.Server.ServerSettings.AutoRestart = false;
NewMessage("Autorestart disabled.", Color.White);
}
#if CLIENT
//TODO: redo again
GameMain.NetLobbyScreen.SetAutoRestart(GameMain.Server.AutoRestart, GameMain.Server.AutoRestartTimer);
#endif
GameMain.NetLobbyScreen.LastUpdateID++;
}
}
@@ -422,6 +445,15 @@ namespace Barotrauma
NewMessage(GameMain.Server.ServerSettings.StartWhenClientsReady ? "Enabled starting the round automatically when clients are ready." : "Disabled starting the round automatically when clients are ready.", Color.White);
});
AssignOnExecute("spawn|spawncharacter", (string[] args) =>
{
SpawnCharacter(args, Vector2.Zero, out string errorMsg);
if (!string.IsNullOrWhiteSpace(errorMsg))
{
ThrowError(errorMsg);
}
});
AssignOnExecute("giveperm", (string[] args) =>
{
if (GameMain.Server == null) return;
@@ -431,11 +463,10 @@ namespace Barotrauma
return;
}
int.TryParse(args[0], out int id);
var client = GameMain.Server.ConnectedClients.Find(c => c.ID == id);
var client = FindClient(args[0]);
if (client == null)
{
ThrowError("Client id \"" + id + "\" not found.");
ThrowError("Client \"" + args[0] + "\" not found.");
return;
}
@@ -455,7 +486,7 @@ namespace Barotrauma
client.GivePermission(permission);
GameMain.Server.UpdateClientPermissions(client);
NewMessage("Granted " + perm + " permissions to " + client.Name + ".", Color.White);
});
}, args, 1);
});
AssignOnExecute("revokeperm", (string[] args) =>
@@ -467,11 +498,15 @@ namespace Barotrauma
return;
}
int.TryParse(args[0], out int id);
var client = GameMain.Server.ConnectedClients.Find(c => c.ID == id);
var client = FindClient(args[0]);
if (client == null)
{
ThrowError("Client id \"" + id + "\" not found.");
ThrowError("Client \"" + args[0] + "\" not found.");
return;
}
if (client.Connection == GameMain.Server.OwnerConnection)
{
NewMessage("Cannot revoke permissions from the server owner!", Color.Red);
return;
}
@@ -491,7 +526,7 @@ namespace Barotrauma
client.RemovePermission(permission);
GameMain.Server.UpdateClientPermissions(client);
NewMessage("Revoked " + perm + " permissions from " + client.Name + ".", Color.White);
});
}, args, 1);
});
AssignOnExecute("giverank", (string[] args) =>
@@ -499,15 +534,19 @@ namespace Barotrauma
if (GameMain.Server == null) return;
if (args.Length < 1)
{
NewMessage("giverank [id]: Assigns a specific rank(= a set of administrative permissions) to the player with the specified client ID.", Color.Cyan);
NewMessage("giverank [id/steamid/endpoint/name] [rank]: Assigns a specific rank (= a set of administrative permissions) to the player with the specified client ID.", Color.Cyan);
return;
}
int.TryParse(args[0], out int id);
var client = GameMain.Server.ConnectedClients.Find(c => c.ID == id);
var client = FindClient(args[0]);
if (client == null)
{
ThrowError("Client id \"" + id + "\" not found.");
ThrowError("Client \"" + args[0] + "\" not found.");
return;
}
if (client.Connection == GameMain.Server.OwnerConnection)
{
NewMessage("Cannot modify the rank of the server owner!", Color.Red);
return;
}
@@ -519,7 +558,7 @@ namespace Barotrauma
ShowQuestionPrompt("Rank to grant to \"" + client.Name + "\"?", (rank) =>
{
PermissionPreset preset = PermissionPreset.List.Find(p => p.Name.ToLowerInvariant() == rank.ToLowerInvariant());
PermissionPreset preset = PermissionPreset.List.Find(p => p.Name.Equals(rank, StringComparison.OrdinalIgnoreCase));
if (preset == null)
{
ThrowError("Rank \"" + rank + "\" not found.");
@@ -529,7 +568,7 @@ namespace Barotrauma
client.SetPermissions(preset.Permissions, preset.PermittedCommands);
GameMain.Server.UpdateClientPermissions(client);
NewMessage("Assigned the rank \"" + preset.Name + "\" to " + client.Name + ".", Color.White);
});
}, args, 1);
});
AssignOnExecute("givecommandperm", (string[] args) =>
@@ -541,11 +580,10 @@ namespace Barotrauma
return;
}
int.TryParse(args[0], out int id);
var client = GameMain.Server.ConnectedClients.Find(c => c.ID == id);
var client = FindClient(args[0]);
if (client == null)
{
ThrowError("Client id \"" + id + "\" not found.");
ThrowError("Client \"" + args[0] + "\" not found.");
return;
}
@@ -571,7 +609,7 @@ namespace Barotrauma
client.SetPermissions(client.Permissions, client.PermittedConsoleCommands.Union(grantedCommands).Distinct().ToList());
GameMain.Server.UpdateClientPermissions(client);
NewMessage("Gave the client \"" + client.Name + "\" the permission to use console commands " + string.Join(", ", grantedCommands.Select(c => c.names[0])) + ".", Color.White);
});
}, args, 1);
});
AssignOnExecute("revokecommandperm", (string[] args) =>
@@ -583,11 +621,15 @@ namespace Barotrauma
return;
}
int.TryParse(args[0], out int id);
var client = GameMain.Server.ConnectedClients.Find(c => c.ID == id);
var client = FindClient(args[0]);
if (client == null)
{
ThrowError("Client id \"" + id + "\" not found.");
ThrowError("Client \"" + args[0] + "\" not found.");
return;
}
if (client.Connection == GameMain.Server.OwnerConnection)
{
NewMessage("Cannot revoke command permissions from the server owner!", Color.Red);
return;
}
@@ -612,7 +654,7 @@ namespace Barotrauma
client.SetPermissions(client.Permissions, client.PermittedConsoleCommands.Except(revokedCommands).ToList());
GameMain.Server.UpdateClientPermissions(client);
NewMessage("Revoked \"" + client.Name + "\"'s permission to use the console commands " + string.Join(", ", revokedCommands.Select(c => c.names[0])) + ".", Color.White);
});
}, args, 1);
});
AssignOnExecute("showperm", (string[] args) =>
@@ -624,11 +666,10 @@ namespace Barotrauma
return;
}
int.TryParse(args[0], out int id);
var client = GameMain.Server.ConnectedClients.Find(c => c.ID == id);
var client = FindClient(args[0]);
if (client == null)
{
ThrowError("Client id \"" + id + "\" not found.");
ThrowError("Client \"" + args[0] + "\" not found.");
return;
}
@@ -667,6 +708,13 @@ namespace Barotrauma
GameMain.Server.ServerSettings.KarmaEnabled = !GameMain.Server.ServerSettings.KarmaEnabled;
NewMessage(GameMain.Server.ServerSettings.KarmaEnabled ? "Karma system enabled." : "Karma system disabled.", Color.LightGreen);
});
AssignOnClientRequestExecute("togglekarma", (Client client, Vector2 cursorWorldPos, string[] args) =>
{
if (GameMain.Server == null) return;
GameMain.Server.ServerSettings.KarmaEnabled = !GameMain.Server.ServerSettings.KarmaEnabled;
NewMessage((GameMain.Server.ServerSettings.KarmaEnabled ? "Karma system enabled by " : "Karma system disabled by ") + client.Name, Color.LightGreen);
GameMain.Server.SendConsoleMessage(GameMain.Server.ServerSettings.KarmaEnabled ? "Karma system enabled." : "Karma system disabled.", client);
});
AssignOnExecute("resetkarma", (string[] args) =>
{
@@ -919,30 +967,20 @@ namespace Barotrauma
CheatsEnabled = true;
SteamAchievementManager.CheatsEnabled = true;
NewMessage("Enabled cheat commands.", Color.Red);
if (Steam.SteamManager.USE_STEAM)
{
NewMessage("Steam achievements have been disabled during this play session.", Color.Red);
GameMain.Server?.UpdateCheatsEnabled();
}
else
{
GameMain.Server?.UpdateCheatsEnabled();
}
#if USE_STEAM
NewMessage("Steam achievements have been disabled during this play session.", Color.Red);
#endif
GameMain.Server?.UpdateCheatsEnabled();
}));
AssignOnClientRequestExecute("enablecheats", (client, cursorPos, args) =>
{
CheatsEnabled = true;
SteamAchievementManager.CheatsEnabled = true;
NewMessage("Cheat commands have been enabled by \"" + client.Name + "\".", Color.Red);
if (Steam.SteamManager.USE_STEAM)
{
NewMessage("Steam achievements have been disabled during this play session.", Color.Red);
GameMain.Server?.UpdateCheatsEnabled();
}
else
{
GameMain.Server?.UpdateCheatsEnabled();
}
#if USE_STEAM
NewMessage("Steam achievements have been disabled during this play session.", Color.Red);
#endif
GameMain.Server?.UpdateCheatsEnabled();
});
commands.Add(new Command("traitorlist", "traitorlist: List all the traitors and their targets.", (string[] args) =>
@@ -1127,7 +1165,7 @@ namespace Barotrauma
else
{
string modeName = string.Join(" ", args);
if (modeName.ToLowerInvariant() == "campaign")
if (modeName.Equals("campaign", StringComparison.OrdinalIgnoreCase))
{
MultiPlayerCampaign.StartCampaignSetup();
}
@@ -1157,9 +1195,8 @@ namespace Barotrauma
};
}));
commands.Add(new Command("mission", "mission [name]/[index]: Select the mission type for the next round. The parameter can either be the name or the index number of the mission type (0 = first mission type, 1 = second mission type, etc).", (string[] args) =>
commands.Add(new Command("mission", "mission [name]: Select the mission type for the next round.", (string[] args) =>
{
int index = -1;
GameMain.NetLobbyScreen.MissionTypeName = string.Join(" ", args);
NewMessage("Set mission to " + GameMain.NetLobbyScreen.MissionTypeName, Color.Cyan);
},
@@ -1430,7 +1467,7 @@ namespace Barotrauma
Character tpCharacter = (args.Length == 0) ? client.Character : FindMatchingCharacter(args, false);
if (tpCharacter == null) return;
var cam = GameMain.GameScreen.Cam;
//var cam = GameMain.GameScreen.Cam;
tpCharacter.AnimController.CurrentHull = null;
tpCharacter.Submarine = null;
tpCharacter.AnimController.SetPosition(ConvertUnits.ToSimUnits(cursorWorldPos));
@@ -1456,7 +1493,7 @@ namespace Barotrauma
{
if (args.Length < 2) return;
AfflictionPrefab afflictionPrefab = AfflictionPrefab.List.Find(a => a.Name.ToLowerInvariant() == args[0].ToLowerInvariant());
AfflictionPrefab afflictionPrefab = AfflictionPrefab.List.FirstOrDefault(a => a.Name.Equals(args[0], StringComparison.OrdinalIgnoreCase));
if (afflictionPrefab == null)
{
GameMain.Server.SendConsoleMessage("Affliction \"" + args[0] + "\" not found.", client);
@@ -1607,11 +1644,10 @@ namespace Barotrauma
{
if (args.Length < 2) return;
int.TryParse(args[0], out int id);
var client = GameMain.Server.ConnectedClients.Find(c => c.ID == id);
var client = FindClient(args[0]);
if (client == null)
{
GameMain.Server.SendConsoleMessage("Client id \"" + id + "\" not found.", senderClient);
ThrowError("Client \"" + args[0] + "\" not found.");
return;
}
@@ -1636,11 +1672,15 @@ namespace Barotrauma
{
if (args.Length < 2) return;
int.TryParse(args[0], out int id);
var client = GameMain.Server.ConnectedClients.Find(c => c.ID == id);
var client = FindClient(args[0]);
if (client == null)
{
GameMain.Server.SendConsoleMessage("Client id \"" + id + "\" not found.", senderClient);
ThrowError("Client \"" + args[0] + "\" not found.");
return;
}
if (client.Connection == GameMain.Server.OwnerConnection)
{
GameMain.Server.SendConsoleMessage("Cannot revoke permissions from the server owner!", senderClient);
return;
}
@@ -1665,16 +1705,20 @@ namespace Barotrauma
{
if (args.Length < 2) return;
int.TryParse(args[0], out int id);
var client = GameMain.Server.ConnectedClients.Find(c => c.ID == id);
var client = FindClient(args[0]);
if (client == null)
{
GameMain.Server.SendConsoleMessage("Client id \"" + id + "\" not found.", senderClient);
ThrowError("Client \"" + args[0] + "\" not found.");
return;
}
if (client.Connection == GameMain.Server.OwnerConnection)
{
GameMain.Server.SendConsoleMessage("Cannot modify the rank of the server owner!", senderClient);
return;
}
string rank = string.Join("", args.Skip(1));
PermissionPreset preset = PermissionPreset.List.Find(p => p.Name.ToLowerInvariant() == rank.ToLowerInvariant());
PermissionPreset preset = PermissionPreset.List.Find(p => p.Name.Equals(rank, StringComparison.OrdinalIgnoreCase));
if (preset == null)
{
GameMain.Server.SendConsoleMessage("Rank \"" + rank + "\" not found.", senderClient);
@@ -1694,11 +1738,15 @@ namespace Barotrauma
{
if (args.Length < 2) return;
int.TryParse(args[0], out int id);
var client = GameMain.Server.ConnectedClients.Find(c => c.ID == id);
var client = FindClient(args[0]);
if (client == null)
{
GameMain.Server.SendConsoleMessage("Client id \"" + id + "\" not found.", senderClient);
ThrowError("Client \"" + args[0] + "\" not found.");
return;
}
if (client.Connection == GameMain.Server.OwnerConnection)
{
GameMain.Server.SendConsoleMessage("Cannot modify the command permissions of the server owner!", senderClient);
return;
}
@@ -1732,11 +1780,15 @@ namespace Barotrauma
{
if (args.Length < 2) return;
int.TryParse(args[0], out int id);
var client = GameMain.Server.ConnectedClients.Find(c => c.ID == id);
var client = FindClient(args[0]);
if (client == null)
{
GameMain.Server.SendConsoleMessage("Client id \"" + id + "\" not found.", senderClient);
ThrowError("Client \"" + args[0] + "\" not found.");
return;
}
if (client.Connection == GameMain.Server.OwnerConnection)
{
GameMain.Server.SendConsoleMessage("Cannot revoke command permissions from the server owner!", senderClient);
return;
}
@@ -1774,11 +1826,10 @@ namespace Barotrauma
return;
}
int.TryParse(args[0], out int id);
var client = GameMain.Server.ConnectedClients.Find(c => c.ID == id);
var client = FindClient(args[0]);
if (client == null)
{
GameMain.Server.SendConsoleMessage("Client id \"" + id + "\" not found.", senderClient);
ThrowError("Client \"" + args[0] + "\" not found.");
return;
}
@@ -1844,8 +1895,7 @@ namespace Barotrauma
"campaigndestination|setcampaigndestination",
(Client senderClient, Vector2 cursorWorldPos, string[] args) =>
{
var campaign = GameMain.GameSession?.GameMode as CampaignMode;
if (campaign == null)
if (!(GameMain.GameSession?.GameMode is CampaignMode campaign))
{
GameMain.Server.SendConsoleMessage("No campaign active!", senderClient);
return;
@@ -1913,16 +1963,16 @@ namespace Barotrauma
{
if (GameMain.Server == null) return;
if (string.IsNullOrWhiteSpace(command)) return;
if (!client.HasPermission(ClientPermissions.ConsoleCommands))
if (!client.HasPermission(ClientPermissions.ConsoleCommands) && client.Connection != GameMain.Server.OwnerConnection)
{
GameMain.Server.SendConsoleMessage("You are not permitted to use console commands!", client);
GameServer.Log(client.Name + " attempted to execute the console command \"" + command + "\" without a permission to use console commands.", ServerLog.MessageType.ConsoleUsage);
return;
}
string[] splitCommand = SplitCommand(command);
string[] splitCommand = ToolBox.SplitCommand(command);
Command matchingCommand = commands.Find(c => c.names.Contains(splitCommand[0].ToLowerInvariant()));
if (matchingCommand != null && !client.PermittedConsoleCommands.Contains(matchingCommand))
if (matchingCommand != null && !client.PermittedConsoleCommands.Contains(matchingCommand) && client.Connection != GameMain.Server.OwnerConnection)
{
GameMain.Server.SendConsoleMessage("You are not permitted to use the command\"" + matchingCommand.names[0] + "\"!", client);
GameServer.Log(client.Name + " attempted to execute the console command \"" + command + "\" without a permission to use the command.", ServerLog.MessageType.ConsoleUsage);
@@ -0,0 +1,16 @@
using Barotrauma.Networking;
namespace Barotrauma
{
partial class CargoMission : Mission
{
public override void ServerWriteInitial(IWriteMessage msg, Client c)
{
msg.Write((ushort)items.Count);
foreach (Item item in items)
{
item.WriteSpawnData(msg, item.ID);
}
}
}
}
@@ -6,10 +6,9 @@ namespace Barotrauma
{
partial class CombatMission
{
private bool[] teamDead = new bool[2];
private readonly bool[] teamDead = new bool[2];
private bool initialized = false;
private int state = 0;
public override string Description
{
@@ -22,7 +21,7 @@ namespace Barotrauma
}
}
public override bool AssignTeamIDs(List<Client> clients)
public override void AssignTeamIDs(List<Client> clients)
{
List<Client> randList = new List<Client>(clients);
for (int i = 0; i < randList.Count; i++)
@@ -45,7 +44,6 @@ namespace Barotrauma
randList[i].TeamID = Character.TeamType.Team2;
}
}
return true;
}
public override void Update(float deltaTime)
@@ -69,8 +67,17 @@ namespace Barotrauma
initialized = true;
}
teamDead[0] = crews[0].All(c => c.IsDead || c.IsUnconscious);
teamDead[1] = crews[1].All(c => c.IsDead || c.IsUnconscious);
if (crews[0].Count == 0 || crews[1].Count == 0)
{
//if there are no characters in either crew, end the round
teamDead[0] = teamDead[1] = true;
state = 1;
}
else
{
teamDead[0] = crews[0].All(c => c.IsDead || c.IsUnconscious);
teamDead[1] = crews[1].All(c => c.IsDead || c.IsUnconscious);
}
if (state == 0)
{
@@ -93,14 +100,18 @@ namespace Barotrauma
if (teamDead[0] && teamDead[1])
{
GameMain.GameSession.WinningTeam = Character.TeamType.None;
if (GameMain.Server != null) GameMain.Server.EndGame();
if (GameMain.Server != null) { GameMain.Server.EndGame(); }
}
else if (GameMain.GameSession.WinningTeam != Character.TeamType.None)
{
GameMain.Server.EndGame();
}
}
}
public override void ServerWriteInitial(IWriteMessage msg, Client c)
{
//do nothing
}
}
}
@@ -0,0 +1,19 @@
using Barotrauma.Networking;
namespace Barotrauma
{
partial class Mission
{
partial void ShowMessageProjSpecific(int missionState)
{
if (missionState >= Headers.Count && missionState >= Messages.Count) return;
string header = missionState < Headers.Count ? Headers[missionState] : "";
string message = missionState < Messages.Count ? Messages[missionState] : "";
GameServer.Log(TextManager.Get("MissionInfo") + ": " + header + " - " + message, ServerLog.MessageType.ServerMessage);
}
public abstract void ServerWriteInitial(IWriteMessage msg, Client c);
}
}
@@ -0,0 +1,22 @@
using Barotrauma.Networking;
using System;
namespace Barotrauma
{
partial class MonsterMission : Mission
{
public override void ServerWriteInitial(IWriteMessage msg, Client c)
{
if (monsters.Count == 0 && monsterFiles.Count > 0)
{
throw new InvalidOperationException("Server attempted to write monster mission data when no monsters had been spawned.");
}
msg.Write((byte)monsters.Count);
foreach (Character monster in monsters)
{
monster.WriteSpawnData(msg, monster.ID, restrictMessageSize: false);
}
}
}
}
@@ -0,0 +1,12 @@
using Barotrauma.Networking;
namespace Barotrauma
{
partial class SalvageMission : Mission
{
public override void ServerWriteInitial(IWriteMessage msg, Client c)
{
item.WriteSpawnData(msg, item.ID);
}
}
}
@@ -61,7 +61,7 @@ namespace Barotrauma
if (vanillaContent == null)
{
// TODO: Dynamic method for defining and finding the vanilla content package.
vanillaContent = ContentPackage.List.SingleOrDefault(cp => Path.GetFileName(cp.Path).ToLowerInvariant() == "vanilla 0.9.xml");
vanillaContent = ContentPackage.List.SingleOrDefault(cp => Path.GetFileName(cp.Path).Equals("vanilla 0.9.xml", StringComparison.OrdinalIgnoreCase));
}
return vanillaContent;
}
@@ -73,7 +73,7 @@ namespace Barotrauma
{
Instance = this;
CommandLineArgs = ToolBox.MergeArguments(args);
CommandLineArgs = args;
World = new World(new Vector2(0, -9.82f));
FarseerPhysics.Settings.AllowSleep = true;
@@ -81,16 +81,24 @@ namespace Barotrauma
FarseerPhysics.Settings.VelocityIterations = 1;
FarseerPhysics.Settings.PositionIterations = 1;
Console.WriteLine("Loading game settings");
Config = new GameSettings();
Console.WriteLine("Loading MD5 hash cache");
Md5Hash.LoadCache();
Console.WriteLine("Initializing SteamManager");
SteamManager.Initialize();
if (GameSettings.SendUserStatistics) GameAnalyticsManager.Init();
Console.WriteLine("Initializing GameAnalytics");
if (GameSettings.SendUserStatistics) GameAnalyticsManager.Init();
Console.WriteLine("Initializing GameScreen");
GameScreen = new GameScreen();
}
public void Init()
{
CharacterPrefab.LoadAll();
MissionPrefab.Init();
TraitorMissionPrefab.Init();
MapEntityPrefab.Init();
@@ -99,10 +107,10 @@ namespace Barotrauma
ScriptedEventSet.LoadPrefabs();
AfflictionPrefab.LoadAll(GetFilesOfType(ContentType.Afflictions));
SkillSettings.Load(GetFilesOfType(ContentType.SkillSettings));
StructurePrefab.LoadAll(GetFilesOfType(ContentType.Structure));
ItemPrefab.LoadAll(GetFilesOfType(ContentType.Item));
JobPrefab.LoadAll(GetFilesOfType(ContentType.Jobs));
ItemAssemblyPrefab.LoadAll();
NPCConversation.LoadAll(GetFilesOfType(ContentType.NPCConversations));
ItemAssemblyPrefab.LoadAll();
LevelObjectPrefab.LoadAll();
@@ -128,13 +136,14 @@ namespace Barotrauma
var exePaths = contentPackage.GetFilesOfType(ContentType.ServerExecutable);
if (exePaths.Count() > 0 && AppDomain.CurrentDomain.FriendlyName != exePaths.First())
{
DebugConsole.NewMessage(AppDomain.CurrentDomain.FriendlyName);
DebugConsole.ShowQuestionPrompt(TextManager.GetWithVariables("IncorrectExe", new string[2] { "[selectedpackage]", "[exename]" }, new string[2] { contentPackage.Name, exePaths.First() }),
(option) =>
{
if (option.ToLower() == "y" || option.ToLower() == "yes")
{
string fullPath = Path.GetFullPath(exePaths.First());
Process.Start(fullPath);
ToolBox.OpenFileWithShell(fullPath);
ShouldRun = false;
}
});
@@ -148,7 +157,7 @@ namespace Barotrauma
/// </summary>
/// <param name="type"></param>
/// <param name="searchAllContentPackages">If true, also returns files in content packages that are installed but not currently selected.</param>
public IEnumerable<string> GetFilesOfType(ContentType type, bool searchAllContentPackages = false)
public IEnumerable<ContentFile> GetFilesOfType(ContentType type, bool searchAllContentPackages = false)
{
if (searchAllContentPackages)
{
@@ -168,6 +177,7 @@ namespace Barotrauma
bool publiclyVisible = false;
string password = "";
bool enableUpnp = false;
int maxPlayers = 10;
int ownerKey = 0;
UInt64 steamId = 0;
@@ -240,6 +250,10 @@ namespace Barotrauma
UInt64.TryParse(CommandLineArgs[i + 1], out steamId);
i++;
break;
case "-pipes":
ChildServerRelay.Start(CommandLineArgs[i + 2], CommandLineArgs[i + 1]);
i += 2;
break;
}
}
@@ -263,6 +277,21 @@ namespace Barotrauma
Server.ServerSettings.PlayStyle = playStyle;
i++;
break;
case "-banafterwrongpassword":
bool.TryParse(CommandLineArgs[i + 1], out bool banAfterWrongPassword);
Server.ServerSettings.BanAfterWrongPassword = banAfterWrongPassword;
break;
case "-karma":
case "-karmaenabled":
bool.TryParse(CommandLineArgs[i + 1], out bool karmaEnabled);
Server.ServerSettings.KarmaEnabled = karmaEnabled;
i++;
break;
case "-karmapreset":
string karmaPresetName = CommandLineArgs[i + 1];
Server.ServerSettings.KarmaPreset = karmaPresetName;
i++;
break;
}
}
}
@@ -304,10 +333,10 @@ namespace Barotrauma
//prevent spiral of death
Timing.Accumulator = Timing.Step;
}
Timing.TotalTime += elapsedTime;
prevTicks = currTicks;
while (Timing.Accumulator >= Timing.Step)
{
Timing.TotalTime += Timing.Step;
DebugConsole.Update();
Screen.Selected?.Update((float)Timing.Step);
Server.Update((float)Timing.Step);
@@ -318,8 +347,23 @@ namespace Barotrauma
Timing.Accumulator -= Timing.Step;
}
#if !DEBUG
if (Server?.OwnerConnection == null && !Console.IsOutputRedirected)
{
DebugConsole.UpdateCommandLine((int)(Timing.Accumulator * 800));
}
else
{
DebugConsole.Clear();
}
#else
DebugConsole.UpdateCommandLine((int)(Timing.Accumulator * 800));
#endif
int frameTime = (int)(((double)(stopwatch.ElapsedTicks - prevTicks) / frequency) * 1000.0);
frameTime = Math.Max(0, frameTime);
Thread.Sleep(Math.Max(((int)(Timing.Step * 1000.0) - frameTime) / 2, 0));
}
stopwatch.Stop();
@@ -328,8 +372,10 @@ namespace Barotrauma
SteamManager.ShutDown();
if (GameSettings.SaveDebugConsoleLogs) DebugConsole.SaveLogs();
if (GameSettings.SendUserStatistics) GameAnalytics.OnQuit();
SaveUtil.CleanUnnecessarySaveFiles();
if (GameSettings.SaveDebugConsoleLogs) { DebugConsole.SaveLogs(); }
if (GameSettings.SendUserStatistics) { GameAnalytics.OnQuit(); }
}
public static void ResetFrameTime()
@@ -46,7 +46,7 @@ namespace Barotrauma
DebugConsole.NewMessage("********* CAMPAIGN SETUP *********", Color.White);
DebugConsole.ShowQuestionPrompt("Do you want to start a new campaign? Y/N", (string arg) =>
{
if (arg.ToLowerInvariant() == "y" || arg.ToLowerInvariant() == "yes")
if (arg.Equals("y", StringComparison.OrdinalIgnoreCase) || arg.Equals("yes", StringComparison.OrdinalIgnoreCase))
{
DebugConsole.ShowQuestionPrompt("Enter a save name for the campaign:", (string saveName) =>
{
@@ -188,7 +188,7 @@ namespace Barotrauma
msg.Write((UInt16)CargoManager.PurchasedItems.Count);
foreach (PurchasedItem pi in CargoManager.PurchasedItems)
{
msg.Write((UInt16)MapEntityPrefab.List.IndexOf(pi.ItemPrefab));
msg.Write(pi.ItemPrefab.Identifier);
msg.Write((UInt16)pi.Quantity);
}
@@ -216,9 +216,9 @@ namespace Barotrauma
List<PurchasedItem> purchasedItems = new List<PurchasedItem>();
for (int i = 0; i < purchasedItemCount; i++)
{
UInt16 itemPrefabIndex = msg.ReadUInt16();
string itemPrefabIdentifier = msg.ReadString();
UInt16 itemQuantity = msg.ReadUInt16();
purchasedItems.Add(new PurchasedItem(MapEntityPrefab.List[itemPrefabIndex] as ItemPrefab, itemQuantity));
purchasedItems.Add(new PurchasedItem(ItemPrefab.Prefabs[itemPrefabIdentifier], itemQuantity));
}
if (!sender.HasPermission(ClientPermissions.ManageCampaign))
@@ -273,10 +273,8 @@ namespace Barotrauma
}
Map.SelectLocation(selectedLocIndex == UInt16.MaxValue ? -1 : selectedLocIndex);
if (Map.SelectedConnection != null)
{
Map.SelectMission(selectedMissionIndex);
}
if (Map.SelectedLocation == null) { Map.SelectRandomLocation(preferUndiscovered: true); }
if (Map.SelectedConnection != null) { Map.SelectMission(selectedMissionIndex); }
List<PurchasedItem> currentItems = new List<PurchasedItem>(CargoManager.PurchasedItems);
foreach (PurchasedItem pi in currentItems)
@@ -294,7 +292,8 @@ namespace Barotrauma
{
XElement modeElement = new XElement("MultiPlayerCampaign",
new XAttribute("money", Money),
new XAttribute("cheatsenabled", CheatsEnabled));
new XAttribute("cheatsenabled", CheatsEnabled),
new XAttribute("initialsuppliesspawned", InitialSuppliesSpawned));
Map.Save(modeElement);
element.Add(modeElement);
@@ -1,5 +1,6 @@
using Microsoft.Xna.Framework;
using Barotrauma.Networking;
using System;
namespace Barotrauma.Items.Components
{
@@ -29,6 +30,7 @@ namespace Barotrauma.Items.Components
msg.Write(isOpen);
msg.Write(extraData.Length == 3 ? (bool)extraData[2] : false); //forced open
msg.WriteRangedSingle(stuck, 0.0f, 100.0f, 8);
msg.Write(lastUser == null ? (UInt16)0 : lastUser.ID);
}
}
}
@@ -0,0 +1,36 @@
using Barotrauma.Networking;
using Microsoft.Xna.Framework;
namespace Barotrauma.Items.Components
{
partial class Holdable : Pickable, IServerSerializable, IClientSerializable
{
public override void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
{
base.ServerWrite(msg, c, extraData);
if (!attachable || body == null) { return; }
msg.Write(Attached);
msg.Write(body.SimPosition.X);
msg.Write(body.SimPosition.Y);
}
public void ServerRead(ClientNetObject type, IReadMessage msg, Client c)
{
Vector2 simPosition = new Vector2(msg.ReadSingle(), msg.ReadSingle());
if (!item.CanClientAccess(c) || !Attachable || attached || !MathUtils.IsValid(simPosition)) { return; }
Vector2 offset = simPosition - c.Character.SimPosition;
offset = offset.ClampLength(MaxAttachDistance * 1.5f);
simPosition = c.Character.SimPosition + offset;
Drop(false, null);
item.SetTransform(simPosition, 0.0f);
AttachToWall();
item.CreateServerEvent(this);
GameServer.Log(c.Character.LogName + " attached " + item.Name + " to a wall", ServerLog.MessageType.ItemInteraction);
}
}
}
@@ -0,0 +1,14 @@
using Barotrauma.Networking;
namespace Barotrauma.Items.Components
{
partial class LevelResource : ItemComponent, IServerSerializable
{
private float lastSentDeattachTimer;
public void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
{
msg.Write(deattachTimer);
}
}
}
@@ -13,7 +13,7 @@ namespace Barotrauma.Items.Components
public void ServerRead(ClientNetObject type, IReadMessage msg, Client c)
{
bool autoTemp = msg.ReadBoolean();
bool shutDown = msg.ReadBoolean();
bool powerOn = msg.ReadBoolean();
float fissionRate = msg.ReadRangedSingle(0.0f, 100.0f, 8);
float turbineOutput = msg.ReadRangedSingle(0.0f, 100.0f, 8);
@@ -24,10 +24,10 @@ namespace Barotrauma.Items.Components
if (!autoTemp && AutoTemp) blameOnBroken = c;
if (turbineOutput < targetTurbineOutput) blameOnBroken = c;
if (fissionRate > targetFissionRate) blameOnBroken = c;
if (!this.shutDown && shutDown) blameOnBroken = c;
if (!_powerOn && powerOn) blameOnBroken = c;
AutoTemp = autoTemp;
this.shutDown = shutDown;
_powerOn = powerOn;
targetFissionRate = fissionRate;
targetTurbineOutput = turbineOutput;
@@ -44,7 +44,7 @@ namespace Barotrauma.Items.Components
public void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
{
msg.Write(autoTemp);
msg.Write(shutDown);
msg.Write(_powerOn);
msg.WriteRangedSingle(temperature, 0.0f, 100.0f, 8);
msg.WriteRangedSingle(targetFissionRate, 0.0f, 100.0f, 8);
msg.WriteRangedSingle(targetTurbineOutput, 0.0f, 100.0f, 8);
@@ -12,7 +12,7 @@ namespace Barotrauma.Items.Components
public void ServerRead(ClientNetObject type, IReadMessage msg, Client c)
{
if (c.Character == null) return;
if (c.Character == null) { return; }
var requestedFixAction = (FixActions)msg.ReadRangedInteger(0, 2);
if (requestedFixAction != FixActions.None)
{
@@ -64,6 +64,12 @@ namespace Barotrauma.Items.Components
}
}
if (!CheckCharacterSuccess(c.Character))
{
GameMain.Server?.CreateEntityEvent(item, new object[] { NetEntityEvent.Type.ApplyStatusEffect, ActionType.OnFailure, this, c.Character.ID });
return;
}
//go through existing wire links
for (int i = 0; i < Connections.Count; i++)
{
@@ -85,7 +91,10 @@ namespace Barotrauma.Items.Components
}
existingWire.RemoveConnection(item);
item.GetComponent<ConnectionPanel>()?.DisconnectedWires.Add(existingWire);
if (existingWire.Item.ParentInventory == null)
{
item.GetComponent<ConnectionPanel>()?.DisconnectedWires.Add(existingWire);
}
if (!wires.Any(w => w.Contains(existingWire)))
{
@@ -95,17 +104,23 @@ namespace Barotrauma.Items.Components
if (existingWire.Connections[0] == null && existingWire.Connections[1] == null)
{
GameServer.Log(c.Character.LogName + " disconnected a wire from " +
Connections[i].Item.Name + " (" + Connections[i].Name + ")", ServerLog.MessageType.ItemInteraction);
Connections[i].Item.Name + " (" + Connections[i].Name + ")", ServerLog.MessageType.Wiring);
if (!clientSideDisconnectedWires.Contains(existingWire))
if (existingWire.Item.ParentInventory != null)
{
//in an inventory and not connected to anything -> the wire cannot have any nodes
existingWire.ClearConnections();
}
else if (!clientSideDisconnectedWires.Contains(existingWire))
{
//not in an inventory, not connected to anything, not hanging loose from any panel -> must be dropped
existingWire.Item.Drop(c.Character);
}
}
else if (existingWire.Connections[0] != null)
{
GameServer.Log(c.Character.LogName + " disconnected a wire from " +
Connections[i].Item.Name + " (" + Connections[i].Name + ") to " + existingWire.Connections[0].Item.Name + " (" + existingWire.Connections[0].Name + ")", ServerLog.MessageType.ItemInteraction);
Connections[i].Item.Name + " (" + Connections[i].Name + ") to " + existingWire.Connections[0].Item.Name + " (" + existingWire.Connections[0].Name + ")", ServerLog.MessageType.Wiring);
//wires that are not in anyone's inventory (i.e. not currently being rewired)
//can never be connected to only one connection
@@ -120,7 +135,7 @@ namespace Barotrauma.Items.Components
else if (existingWire.Connections[1] != null)
{
GameServer.Log(c.Character.LogName + " disconnected a wire from " +
Connections[i].Item.Name + " (" + Connections[i].Name + ") to " + existingWire.Connections[1].Item.Name + " (" + existingWire.Connections[1].Name + ")", ServerLog.MessageType.ItemInteraction);
Connections[i].Item.Name + " (" + Connections[i].Name + ") to " + existingWire.Connections[1].Item.Name + " (" + existingWire.Connections[1].Name + ")", ServerLog.MessageType.Wiring);
/*if (existingWire.Item.ParentInventory == null && !wires.Any(w => w.Contains(existingWire)))
{
@@ -139,7 +154,8 @@ namespace Barotrauma.Items.Components
{
if (disconnectedWire.Connections[0] == null &&
disconnectedWire.Connections[1] == null &&
!clientSideDisconnectedWires.Contains(disconnectedWire))
!clientSideDisconnectedWires.Contains(disconnectedWire) &&
disconnectedWire.Item.ParentInventory == null)
{
disconnectedWire.Item.Drop(c.Character);
GameServer.Log(c.Character.LogName + " dropped " + disconnectedWire.Name, ServerLog.MessageType.Inventory);
@@ -163,14 +179,14 @@ namespace Barotrauma.Items.Components
{
GameServer.Log(c.Character.LogName + " connected a wire to " +
Connections[i].Item.Name + " (" + Connections[i].Name + ")",
ServerLog.MessageType.ItemInteraction);
ServerLog.MessageType.Wiring);
}
else
{
GameServer.Log(c.Character.LogName + " connected a wire from " +
Connections[i].Item.Name + " (" + Connections[i].Name + ") to " +
(otherConnection == null ? "none" : otherConnection.Item.Name + " (" + (otherConnection.Name) + ")"),
ServerLog.MessageType.ItemInteraction);
ServerLog.MessageType.Wiring);
}
}
}
@@ -0,0 +1,31 @@
using Barotrauma.Networking;
namespace Barotrauma.Items.Components
{
partial class Terminal : ItemComponent, IClientSerializable, IServerSerializable
{
public void ServerRead(ClientNetObject type, IReadMessage msg, Client c)
{
string newOutputValue = msg.ReadString();
if (item.CanClientAccess(c))
{
if (newOutputValue.Length > MaxMessageLength)
{
newOutputValue = newOutputValue.Substring(0, MaxMessageLength);
}
GameServer.Log(c.Character.LogName + " entered \"" + newOutputValue + "\" on " + item.Name,
ServerLog.MessageType.ItemInteraction);
OutputValue = newOutputValue;
item.SendSignal(0, newOutputValue, "signal_out", null);
item.CreateServerEvent(this);
}
}
public void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
{
msg.Write(OutputValue);
}
}
}
@@ -1,10 +1,6 @@
using Barotrauma.Networking;
using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Xml.Linq;
namespace Barotrauma.Items.Components
{
@@ -19,7 +15,6 @@ namespace Barotrauma.Items.Components
{
GameMain.Server.CreateEntityEvent(item, new object[] { NetEntityEvent.Type.ComponentState, item.GetComponentIndex(this), i });
}
}
public void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
@@ -36,5 +31,34 @@ namespace Barotrauma.Items.Components
msg.Write(nodes[i].Y);
}
}
public void ServerRead(ClientNetObject type, IReadMessage msg, Client c)
{
int nodeCount = msg.ReadByte();
Vector2 lastNodePos = Vector2.Zero;
if (nodeCount > 0)
{
lastNodePos = new Vector2(msg.ReadSingle(), msg.ReadSingle());
}
if (!item.CanClientAccess(c)) { return; }
if (nodes.Count > nodeCount)
{
nodes.RemoveRange(nodeCount, nodes.Count - nodeCount);
}
if (nodeCount > 0)
{
if (nodeCount > nodes.Count)
{
nodes.Add(lastNodePos);
}
else
{
nodes[nodes.Count - 1] = lastNodePos;
}
}
CreateNetworkEvent();
}
}
}
@@ -8,6 +8,11 @@ namespace Barotrauma
{
partial class Item : MapEntity, IDamageable, ISerializableEntity, IServerSerializable, IClientSerializable
{
public override Sprite Sprite
{
get { return prefab?.sprite; }
}
public void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
{
string errorMsg = "";
@@ -75,6 +80,7 @@ namespace Barotrauma
break;
}
msg.WriteRangedInteger(containerIndex, 0, components.Count - 1);
msg.Write(GameMain.Server.EntityEventManager.Events.Last()?.ID ?? (ushort)0);
(components[containerIndex] as ItemContainer).Inventory.ServerWrite(msg, c);
break;
case NetEntityEvent.Type.Status:
@@ -306,7 +312,7 @@ namespace Barotrauma
public float GetPositionUpdateInterval(Client recipient)
{
if (PositionUpdateInterval == float.PositiveInfinity)
if (PositionUpdateInterval == float.PositiveInfinity || body == null || parentInventory != null)
{
return float.PositiveInfinity;
}
@@ -344,7 +350,7 @@ namespace Barotrauma
IWriteMessage tempBuffer = new WriteOnlyMessage();
body.ServerWrite(tempBuffer, c, extraData);
msg.Write((byte)tempBuffer.LengthBytes);
msg.WriteVariableUInt32((uint)tempBuffer.LengthBytes);
msg.Write(tempBuffer.Buffer, 0, tempBuffer.LengthBytes);
msg.WritePadBits();
}
@@ -62,6 +62,8 @@ namespace Barotrauma.Networking
partial class BanList
{
const string SavePath = "Data/bannedplayers.txt";
partial void InitProjectSpecific()
{
if (!File.Exists(SavePath)) { return; }
@@ -117,23 +119,32 @@ namespace Barotrauma.Networking
}
}
public bool IsBanned(IPAddress IP, ulong steamID)
public bool IsBanned(IPAddress IP, ulong steamID, out string reason)
{
reason = string.Empty;
if (IPAddress.IsLoopback(IP)) { return false; }
return bannedPlayers.Any(bp => bp.CompareTo(IP) || (steamID > 0 && bp.SteamID == steamID));
var bannedPlayer = bannedPlayers.Find(bp => bp.CompareTo(IP) || (steamID > 0 && bp.SteamID == steamID));
reason = bannedPlayer?.Reason;
return bannedPlayer != null;
}
public bool IsBanned(IPAddress IP)
public bool IsBanned(IPAddress IP, out string reason)
{
reason = string.Empty;
if (IPAddress.IsLoopback(IP)) { return false; }
bannedPlayers.RemoveAll(bp => bp.ExpirationTime.HasValue && DateTime.Now > bp.ExpirationTime.Value);
return bannedPlayers.Any(bp => bp.CompareTo(IP));
var bannedPlayer = bannedPlayers.Find(bp => bp.CompareTo(IP));
reason = bannedPlayer?.Reason;
return bannedPlayer != null;
}
public bool IsBanned(ulong steamID)
public bool IsBanned(ulong steamID, out string reason)
{
reason = string.Empty;
bannedPlayers.RemoveAll(bp => bp.ExpirationTime.HasValue && DateTime.Now > bp.ExpirationTime.Value);
return bannedPlayers.Any(bp => (steamID > 0 && bp.SteamID == steamID));
var bannedPlayer = bannedPlayers.Find(bp => steamID > 0 && bp.SteamID == steamID);
reason = bannedPlayer?.Reason;
return bannedPlayer != null;
}
public void BanPlayer(string name, IPAddress ip, string reason, TimeSpan? duration)
@@ -0,0 +1,30 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.Pipes;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Win32.SafeHandles;
namespace Barotrauma.Networking
{
static partial class ChildServerRelay
{
public static void Start(string writeHandle, string readHandle)
{
var writePipe = new AnonymousPipeClientStream(PipeDirection.Out, writeHandle);
var readPipe = new AnonymousPipeClientStream(PipeDirection.In, readHandle);
writeStream = writePipe; readStream = readPipe;
PrivateStart();
}
public static void ShutDown()
{
PrivateShutDown();
}
}
}
@@ -94,12 +94,15 @@ namespace Barotrauma.Networking
partial void InitProjSpecific()
{
var jobs = JobPrefab.List.Values.ToList();
var jobs = JobPrefab.Prefabs.ToList();
// TODO: modding support?
JobPreferences = new List<Pair<JobPrefab, int>>(jobs.GetRange(0, Math.Min(jobs.Count, 3)).Select(j => new Pair<JobPrefab, int>(j, 0)));
VoipQueue = new VoipQueue(ID, true, true);
GameMain.Server.VoipServer.RegisterQueue(VoipQueue);
//initialize to infinity, gets set to a proper value when initializing midround syncing
MidRoundSyncTimeOut = double.PositiveInfinity;
}
partial void DisposeProjSpecific()
@@ -41,7 +41,7 @@ namespace Barotrauma
{
message.Write((byte)SpawnableType.Character);
DebugConsole.Log("Writing character spawn data: " + entities.Entity.ToString() + " (original ID: " + entities.OriginalID + ", current ID: " + entities.Entity.ID + ")");
((Character)entities.Entity).WriteSpawnData(message, entities.OriginalID);
((Character)entities.Entity).WriteSpawnData(message, entities.OriginalID, restrictMessageSize: true);
}
}
}
@@ -2,7 +2,6 @@
using Barotrauma.Items.Components;
using Lidgren.Network;
using Microsoft.Xna.Framework;
using RestSharp;
using System;
using System.Collections.Generic;
using System.Diagnostics;
@@ -60,10 +59,6 @@ namespace Barotrauma.Networking
private DateTime roundStartTime;
private RestClient restClient;
private bool masterServerResponded;
private IRestResponse masterServerResponse;
private bool autoRestartTimerRunning;
private float endRoundTimer;
@@ -197,14 +192,9 @@ namespace Barotrauma.Networking
if (serverPeer is LidgrenServerPeer)
{
if (SteamManager.USE_STEAM)
{
registeredToMaster = SteamManager.CreateServer(this, isPublic);
}
if (isPublic && !GameMain.Config.UseSteamMatchmaking)
{
CoroutineManager.StartCoroutine(RegisterToMasterServer());
}
#if USE_STEAM
registeredToMaster = SteamManager.CreateServer(this, isPublic);
#endif
}
TickRate = serverSettings.TickRate;
@@ -330,129 +320,6 @@ namespace Barotrauma.Networking
DisconnectClient(connectedClient, reason: disconnectMsg);
}
private IEnumerable<object> RegisterToMasterServer()
{
if (restClient == null)
{
restClient = new RestClient(NetConfig.MasterServerUrl);
}
var request = new RestRequest("masterserver3.php", Method.GET);
request.AddParameter("action", "addserver");
request.AddParameter("servername", serverName);
request.AddParameter("serverport", Port);
request.AddParameter("currplayers", connectedClients.Count);
request.AddParameter("maxplayers", serverSettings.MaxPlayers);
request.AddParameter("password", serverSettings.HasPassword ? 0 : 1);
request.AddParameter("version", GameMain.Version.ToString());
if (GameMain.Config.SelectedContentPackages.Count > 0)
{
request.AddParameter("contentpackages", string.Join(",", GameMain.Config.SelectedContentPackages.Select(cp => cp.Name)));
}
masterServerResponded = false;
masterServerResponse = null;
var restRequestHandle = restClient.ExecuteAsync(request, response => MasterServerCallBack(response));
DateTime timeOut = DateTime.Now + new TimeSpan(0, 0, 15);
while (!masterServerResponded)
{
if (DateTime.Now > timeOut)
{
restRequestHandle.Abort();
DebugConsole.NewMessage("Couldn't register to master server (request timed out)", Color.Red);
Log("Couldn't register to master server (request timed out)", ServerLog.MessageType.Error);
yield return CoroutineStatus.Success;
}
yield return CoroutineStatus.Running;
}
if (masterServerResponse.StatusCode != System.Net.HttpStatusCode.OK)
{
DebugConsole.ThrowError("Error while connecting to master server (" + masterServerResponse.StatusCode + ": " + masterServerResponse.StatusDescription + ")");
}
else if (masterServerResponse != null && !string.IsNullOrWhiteSpace(masterServerResponse.Content))
{
DebugConsole.ThrowError("Error while connecting to master server (" + masterServerResponse.Content + ")");
}
else
{
registeredToMaster = true;
refreshMasterTimer = DateTime.Now + refreshMasterInterval;
}
yield return CoroutineStatus.Success;
}
private IEnumerable<object> RefreshMaster()
{
if (restClient == null)
{
restClient = new RestClient(NetConfig.MasterServerUrl);
}
var request = new RestRequest("masterserver3.php", Method.GET);
request.AddParameter("action", "refreshserver");
request.AddParameter("serverport", Port);
request.AddParameter("gamestarted", gameStarted ? 1 : 0);
request.AddParameter("currplayers", connectedClients.Count);
request.AddParameter("maxplayers", serverSettings.MaxPlayers);
Log("Refreshing connection with master server...", ServerLog.MessageType.ServerMessage);
var sw = new Stopwatch();
sw.Start();
masterServerResponded = false;
masterServerResponse = null;
var restRequestHandle = restClient.ExecuteAsync(request, response => MasterServerCallBack(response));
DateTime timeOut = DateTime.Now + new TimeSpan(0, 0, 15);
while (!masterServerResponded)
{
if (DateTime.Now > timeOut)
{
restRequestHandle.Abort();
DebugConsole.NewMessage("Couldn't connect to master server (request timed out)", Color.Red);
Log("Couldn't connect to master server (request timed out)", ServerLog.MessageType.Error);
yield return CoroutineStatus.Success;
}
yield return CoroutineStatus.Running;
}
if (masterServerResponse.Content == "Error: server not found")
{
Log("Not registered to master server, re-registering...", ServerLog.MessageType.Error);
CoroutineManager.StartCoroutine(RegisterToMasterServer());
}
else if (masterServerResponse.ErrorException != null)
{
DebugConsole.NewMessage("Error while registering to master server (" + masterServerResponse.ErrorException + ")", Color.Red);
Log("Error while registering to master server (" + masterServerResponse.ErrorException + ")", ServerLog.MessageType.Error);
}
else if (masterServerResponse.StatusCode != System.Net.HttpStatusCode.OK)
{
DebugConsole.NewMessage("Error while reporting to master server (" + masterServerResponse.StatusCode + ": " + masterServerResponse.StatusDescription + ")", Color.Red);
Log("Error while reporting to master server (" + masterServerResponse.StatusCode + ": " + masterServerResponse.StatusDescription + ")", ServerLog.MessageType.Error);
}
else
{
Log("Master server responded", ServerLog.MessageType.ServerMessage);
}
System.Diagnostics.Debug.WriteLine("took " + sw.ElapsedMilliseconds + " ms");
yield return CoroutineStatus.Success;
}
private void MasterServerCallBack(IRestResponse response)
{
masterServerResponse = response;
masterServerResponded = true;
}
public override void Update(float deltaTime)
{
#if CLIENT
@@ -460,6 +327,12 @@ namespace Barotrauma.Networking
#endif
if (!started) { return; }
if (OwnerConnection != null && ChildServerRelay.HasShutDown)
{
Disconnect();
return;
}
base.Update(deltaTime);
fileSender.Update(deltaTime);
@@ -484,18 +357,20 @@ namespace Barotrauma.Networking
character.KillDisconnectedTimer += deltaTime;
character.SetStun(1.0f);
if (character.KillDisconnectedTimer > serverSettings.KillDisconnectedTime)
Client owner = connectedClients.Find(c =>
c.Name == character.OwnerClientName &&
c.EndpointMatches(character.OwnerClientEndPoint));
if ((OwnerConnection == null || owner?.Connection != OwnerConnection) && character.KillDisconnectedTimer > serverSettings.KillDisconnectedTime)
{
character.Kill(CauseOfDeathType.Disconnected, null);
continue;
}
Client owner = connectedClients.Find(c =>
c.InGame && !c.NeedsMidRoundSync &&
c.Name == character.OwnerClientName &&
c.EndpointMatches(character.OwnerClientEndPoint));
if (owner != null && (!serverSettings.AllowSpectating || !owner.SpectateOnly))
if (owner != null &&
owner.InGame && !owner.NeedsMidRoundSync &&
(!serverSettings.AllowSpectating || !owner.SpectateOnly))
{
SetClientCharacter(owner, character);
}
@@ -731,10 +606,6 @@ namespace Barotrauma.Networking
"Refreshing server info on the server list failed.", ServerLog.MessageType.ServerMessage);
}
}
else
{
CoroutineManager.StartCoroutine(RefreshMaster());
}
refreshMasterTimer = DateTime.Now + refreshMasterInterval;
serverSettings.ServerDetailsChanged = false;
}
@@ -756,10 +627,16 @@ namespace Barotrauma.Networking
//game already started -> send start message immediately
if (gameStarted)
{
SendStartMessage(roundStartSeed, Submarine.MainSub, GameMain.GameSession.GameMode.Preset, connectedClient);
SendStartMessage(roundStartSeed, GameMain.GameSession.Level.Seed, GameMain.GameSession, connectedClient, true);
}
}
break;
case ClientPacketHeader.REQUEST_STARTGAMEFINALIZE:
if (gameStarted && connectedClient != null)
{
SendRoundStartFinalize(connectedClient);
}
break;
case ClientPacketHeader.UPDATE_LOBBY:
ClientReadLobby(inc);
break;
@@ -879,6 +756,15 @@ namespace Barotrauma.Networking
Log(c.Name + " has reported an error: " + errorStr, ServerLog.MessageType.Error);
GameAnalyticsManager.AddErrorEventOnce("GameServer.HandleClientError:" + errorStr, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorStr);
try
{
WriteEventErrorData(c, errorStr);
}
catch (Exception e)
{
DebugConsole.ThrowError("Failed to write event error data", e);
}
if (c.Connection == OwnerConnection)
{
SendDirectChatMessage(errorStr, c, ChatMessageType.MessageBox);
@@ -888,6 +774,69 @@ namespace Barotrauma.Networking
{
KickClient(c, errorStr);
}
}
private void WriteEventErrorData(Client client, string errorStr)
{
if (!Directory.Exists(ServerLog.SavePath))
{
Directory.CreateDirectory(ServerLog.SavePath);
}
string filePath = "event_error_log_server_" + client.Name + "_" + DateTime.UtcNow.ToShortTimeString() + ".log";
filePath = Path.Combine(ServerLog.SavePath, ToolBox.RemoveInvalidFileNameChars(filePath));
if (File.Exists(filePath)) { return; }
List<string> errorLines = new List<string>
{
errorStr, ""
};
if (GameMain.GameSession?.GameMode != null)
{
errorLines.Add("Game mode: " + GameMain.GameSession.GameMode.Name);
}
if (GameMain.GameSession?.Submarine != null)
{
errorLines.Add("Submarine: " + GameMain.GameSession.Submarine.Name);
}
if (Level.Loaded != null)
{
errorLines.Add("Level: " + Level.Loaded.Seed + ", " + Level.Loaded.EqualityCheckVal);
}
errorLines.Add("Entity IDs:");
List<Entity> sortedEntities = Entity.GetEntityList();
sortedEntities.Sort((e1, e2) => e1.ID.CompareTo(e2.ID));
foreach (Entity e in sortedEntities)
{
errorLines.Add(e.ID + ": " + e.ToString());
}
errorLines.Add("");
errorLines.Add("EntitySpawner events:");
foreach (var entityEvent in entityEventManager.UniqueEvents)
{
if (entityEvent.Entity is EntitySpawner)
{
var spawnData = entityEvent.Data[0] as EntitySpawner.SpawnOrRemove;
errorLines.Add(
entityEvent.ID + ": " +
(spawnData.Remove ? "Remove " : "Create ") +
spawnData.Entity.ToString() +
" (" + spawnData.OriginalID + ", " + spawnData.Entity.ID + ")");
}
}
errorLines.Add("");
errorLines.Add("Last debug messages:");
for (int i = DebugConsole.Messages.Count - 1; i > 0 && i > DebugConsole.Messages.Count - 15; i--)
{
errorLines.Add(" " + DebugConsole.Messages[i].Time + " - " + DebugConsole.Messages[i].Text);
}
File.WriteAllLines(filePath, errorLines);
}
public override void CreateEntityEvent(INetSerializable entity, object[] extraData = null)
@@ -978,12 +927,14 @@ namespace Barotrauma.Networking
return;
}
bool midroundSyncingDone = inc.ReadBoolean();
inc.ReadPadBits();
if (gameStarted)
{
if (!c.InGame)
{
//check if midround syncing is needed due to missed unique events
entityEventManager.InitClientMidRoundSync(c);
if (!midroundSyncingDone) { entityEventManager.InitClientMidRoundSync(c); }
c.InGame = true;
}
}
@@ -1021,8 +972,7 @@ namespace Barotrauma.Networking
}
}
if (NetIdUtils.IdMoreRecent(lastRecvChatMsgID, c.LastRecvChatMsgID) && //more recent than the last ID received by the client
!NetIdUtils.IdMoreRecent(lastRecvChatMsgID, c.LastChatMsgQueueID)) //NOT more recent than the latest existing ID
if (NetIdUtils.IsValidId(lastRecvChatMsgID, c.LastRecvChatMsgID, c.LastChatMsgQueueID))
{
c.LastRecvChatMsgID = lastRecvChatMsgID;
}
@@ -1033,8 +983,7 @@ namespace Barotrauma.Networking
" (previous: " + c.LastChatMsgQueueID + ", latest: " + c.LastChatMsgQueueID + ")");
}
if (NetIdUtils.IdMoreRecent(lastRecvEntityEventID, c.LastRecvEntityEventID) &&
!NetIdUtils.IdMoreRecent(lastRecvEntityEventID, lastEntityEventID))
if (NetIdUtils.IsValidId(lastRecvEntityEventID, c.LastRecvEntityEventID, lastEntityEventID))
{
if (c.NeedsMidRoundSync)
{
@@ -1129,7 +1078,7 @@ namespace Barotrauma.Networking
case ClientPermissions.Kick:
string kickedName = inc.ReadString().ToLowerInvariant();
string kickReason = inc.ReadString();
var kickedClient = connectedClients.Find(cl => cl != sender && cl.Name.ToLowerInvariant() == kickedName && cl.Connection != OwnerConnection);
var kickedClient = connectedClients.Find(cl => cl != sender && cl.Name.Equals(kickedName, StringComparison.OrdinalIgnoreCase) && cl.Connection != OwnerConnection);
if (kickedClient != null)
{
Log("Client \"" + sender.Name + "\" kicked \"" + kickedClient.Name + "\".", ServerLog.MessageType.ServerMessage);
@@ -1146,7 +1095,7 @@ namespace Barotrauma.Networking
bool range = inc.ReadBoolean();
double durationSeconds = inc.ReadDouble();
var bannedClient = connectedClients.Find(cl => cl != sender && cl.Name.ToLowerInvariant() == bannedName && cl.Connection != OwnerConnection);
var bannedClient = connectedClients.Find(cl => cl != sender && cl.Name.Equals(bannedName, StringComparison.OrdinalIgnoreCase) && cl.Connection != OwnerConnection);
if (bannedClient != null)
{
Log("Client \"" + sender.Name + "\" banned \"" + bannedClient.Name + "\".", ServerLog.MessageType.ServerMessage);
@@ -1205,7 +1154,7 @@ namespace Barotrauma.Networking
break;
case ClientPermissions.SelectMode:
UInt16 modeIndex = inc.ReadUInt16();
if (GameMain.NetLobbyScreen.GameModes[modeIndex].Identifier.ToLowerInvariant() == "multiplayercampaign")
if (GameMain.NetLobbyScreen.GameModes[modeIndex].Identifier.Equals("multiplayercampaign", StringComparison.OrdinalIgnoreCase))
{
string[] saveFiles = SaveUtil.GetSaveFiles(SaveUtil.SaveType.Multiplayer).ToArray();
for (int i = 0; i < saveFiles.Length; i++)
@@ -1217,7 +1166,8 @@ namespace Barotrauma.Networking
string.Join(";",
saveFiles[i].Replace(';', ' '),
doc.Root.GetAttributeString("submarine", ""),
doc.Root.GetAttributeString("savetime", ""));
doc.Root.GetAttributeString("savetime", ""),
doc.Root.GetAttributeString("selectedcontentpackages", ""));
}
}
@@ -1402,7 +1352,7 @@ namespace Barotrauma.Networking
if (item.PositionUpdateInterval == float.PositiveInfinity) { continue; }
float updateInterval = item.GetPositionUpdateInterval(c);
c.PositionUpdateLastSent.TryGetValue(item.ID, out float lastSent);
if (lastSent > Lidgren.Network.NetTime.Now - item.PositionUpdateInterval) { continue; }
if (lastSent > Lidgren.Network.NetTime.Now - updateInterval) { continue; }
if (!c.PendingPositionUpdates.Contains(item)) c.PendingPositionUpdates.Enqueue(item);
}
}
@@ -1829,10 +1779,10 @@ namespace Barotrauma.Networking
//always allow the server owner to spectate even if it's disallowed in server settings
playingClients.RemoveAll(c => c.Connection == OwnerConnection && c.SpectateOnly);
if (GameMain.GameSession.GameMode.Mission != null &&
GameMain.GameSession.GameMode.Mission.AssignTeamIDs(playingClients))
if (GameMain.GameSession.GameMode.Mission != null)
{
teamCount = 2;
GameMain.GameSession.GameMode.Mission.AssignTeamIDs(playingClients);
teamCount = GameMain.GameSession.GameMode.Mission.TeamCount;
}
else
{
@@ -1841,9 +1791,21 @@ namespace Barotrauma.Networking
if (campaign != null)
{
if (campaign.Map == null)
{
throw new Exception("Campaign map was null.");
}
if (campaign.Map.SelectedConnection == null)
{
//this should not happen, there should always be some destination selected
DebugConsole.ThrowError("No connection between locations was selected when starting the round. Choosing a random location...");
campaign.Map.SelectRandomLocation(preferUndiscovered: true);
}
SendStartMessage(roundStartSeed, campaign.Map.SelectedConnection.Level.Seed, GameMain.GameSession, connectedClients, false);
GameMain.GameSession.StartRound(campaign.Map.SelectedConnection.Level,
reloadSub: true,
loadSecondSub: teamCount > 1,
mirrorLevel: campaign.Map.CurrentLocation != campaign.Map.SelectedConnection.Locations[0]);
campaign.AssignClientCharacterInfos(connectedClients);
@@ -1853,7 +1815,9 @@ namespace Barotrauma.Networking
}
else
{
GameMain.GameSession.StartRound(GameMain.NetLobbyScreen.LevelSeed, serverSettings.SelectedLevelDifficulty, teamCount > 1);
SendStartMessage(roundStartSeed, GameMain.NetLobbyScreen.LevelSeed, GameMain.GameSession, connectedClients, false);
GameMain.GameSession.StartRound(GameMain.NetLobbyScreen.LevelSeed, serverSettings.SelectedLevelDifficulty);
Log("Game mode: " + selectedMode.Name, ServerLog.MessageType.ServerMessage);
Log("Submarine: " + selectedSub.Name, ServerLog.MessageType.ServerMessage);
Log("Level seed: " + GameMain.NetLobbyScreen.LevelSeed, ServerLog.MessageType.ServerMessage);
@@ -1872,6 +1836,8 @@ namespace Barotrauma.Networking
if (serverSettings.AllowRespawn && missionAllowRespawn) { respawnManager = new RespawnManager(this, usingShuttle ? selectedShuttle : null); }
AutoItemPlacer.PlaceIfNeeded(GameMain.GameSession.GameMode);
entityEventManager.RefreshEntityIDs();
//assign jobs and spawnpoints separately for each team
@@ -1911,7 +1877,7 @@ namespace Barotrauma.Networking
if (client.CharacterInfo == null)
{
client.CharacterInfo = new CharacterInfo(Character.HumanSpeciesName, client.Name);
client.CharacterInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, client.Name);
}
characterInfos.Add(client.CharacterInfo);
if (client.CharacterInfo.Job == null || client.CharacterInfo.Job.Prefab != client.AssignedJob.First)
@@ -1924,7 +1890,7 @@ namespace Barotrauma.Networking
int botsToSpawn = serverSettings.BotSpawnMode == BotSpawnMode.Fill ? serverSettings.BotCount - characterInfos.Count : serverSettings.BotCount;
for (int i = 0; i < botsToSpawn; i++)
{
var botInfo = new CharacterInfo(Character.HumanSpeciesName)
var botInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName)
{
TeamID = teamID
};
@@ -1982,11 +1948,6 @@ namespace Barotrauma.Networking
{
if (!(GameMain.GameSession?.GameMode is CampaignMode))
{
List<Character> characters = new List<Character>();
foreach (Client client in ConnectedClients)
{
if (client.Character != null) characters.Add(client.Character);
}
TraitorManager = new TraitorManager();
TraitorManager.Start(this);
}
@@ -1994,11 +1955,8 @@ namespace Barotrauma.Networking
GameAnalyticsManager.AddDesignEvent("Traitors:" + (TraitorManager == null ? "Disabled" : "Enabled"));
SendStartMessage(roundStartSeed, Submarine.MainSub, GameMain.GameSession.GameMode.Preset, connectedClients);
yield return CoroutineStatus.Running;
GameMain.GameScreen.Cam.TargetPos = Vector2.Zero;
GameMain.GameScreen.Select();
Log("Round started.", ServerLog.MessageType.ServerMessage);
@@ -2014,35 +1972,34 @@ namespace Barotrauma.Networking
yield return CoroutineStatus.Success;
}
private void SendStartMessage(int seed, Submarine selectedSub, GameModePreset selectedMode, List<Client> clients)
private void SendStartMessage(int seed, string levelSeed, GameSession gameSession, List<Client> clients, bool includesFinalize)
{
foreach (Client client in clients)
{
SendStartMessage(seed, selectedSub, selectedMode, client);
SendStartMessage(seed, levelSeed, gameSession, client, includesFinalize);
}
}
private void SendStartMessage(int seed, Submarine selectedSub, GameModePreset selectedMode, Client client)
private void SendStartMessage(int seed, string levelSeed, GameSession gameSession, Client client, bool includesFinalize)
{
IWriteMessage msg = new WriteOnlyMessage();
msg.Write((byte)ServerPacketHeader.STARTGAME);
msg.Write(seed);
msg.Write(GameMain.GameSession.Level.Seed);
msg.Write(GameMain.GameSession.Level.EqualityCheckVal);
msg.Write(levelSeed);
msg.Write(serverSettings.SelectedLevelDifficulty);
msg.Write((byte)GameMain.Config.LosMode);
msg.Write((byte)GameMain.NetLobbyScreen.MissionType);
msg.Write(selectedSub.Name);
msg.Write(selectedSub.MD5Hash.Hash);
msg.Write(gameSession.Submarine.Name);
msg.Write(gameSession.Submarine.MD5Hash.Hash);
msg.Write(serverSettings.UseRespawnShuttle);
msg.Write(GameMain.NetLobbyScreen.SelectedShuttle.Name);
msg.Write(GameMain.NetLobbyScreen.SelectedShuttle.MD5Hash.Hash);
msg.Write(selectedMode.Identifier);
msg.Write(gameSession.GameMode.Preset.Identifier);
msg.Write((short)(GameMain.GameSession.GameMode?.Mission == null ?
-1 : MissionPrefab.List.IndexOf(GameMain.GameSession.GameMode.Mission.Prefab)));
@@ -2051,7 +2008,6 @@ namespace Barotrauma.Networking
MissionMode missionMode = GameMain.GameSession.GameMode as MissionMode;
bool missionAllowRespawn = campaign == null && (missionMode?.Mission == null || missionMode.Mission.AllowRespawn);
msg.Write(serverSettings.AllowRespawn && missionAllowRespawn);
msg.Write(Submarine.MainSubs[1] != null); //loadSecondSub
msg.Write(serverSettings.AllowDisguises);
msg.Write(serverSettings.AllowRewiring);
@@ -2060,9 +2016,48 @@ namespace Barotrauma.Networking
serverSettings.WriteMonsterEnabled(msg);
msg.Write(includesFinalize); msg.WritePadBits();
if (includesFinalize)
{
WriteRoundStartFinalize(msg, client);
}
serverPeer.Send(msg, client.Connection, DeliveryMethod.Reliable);
}
private void SendRoundStartFinalize(List<Client> clients)
{
foreach (Client client in clients)
{
SendRoundStartFinalize(client);
}
}
private void SendRoundStartFinalize(Client client)
{
IWriteMessage msg = new WriteOnlyMessage();
msg.Write((byte)ServerPacketHeader.STARTGAMEFINALIZE);
WriteRoundStartFinalize(msg, client);
serverPeer.Send(msg, client.Connection, DeliveryMethod.Reliable);
}
private void WriteRoundStartFinalize(IWriteMessage msg, Client client)
{
//tell the client what content files they should preload
var contentToPreload = GameMain.GameSession.EventManager.GetFilesToPreload();
msg.Write((ushort)contentToPreload.Count());
foreach (ContentFile contentFile in contentToPreload)
{
msg.Write((byte)contentFile.Type);
msg.Write(contentFile.Path);
}
msg.Write(GameMain.GameSession.Level.EqualityCheckVal);
GameMain.GameSession.Mission?.ServerWriteInitial(msg, client);
}
public void EndGame()
{
if (!gameStarted)
@@ -2208,11 +2203,9 @@ namespace Barotrauma.Networking
public override void KickPlayer(string playerName, string reason)
{
playerName = playerName.ToLowerInvariant();
Client client = connectedClients.Find(c =>
c.Name.ToLowerInvariant() == playerName ||
(c.Character != null && c.Character.Name.ToLowerInvariant() == playerName));
c.Name.Equals(playerName, StringComparison.OrdinalIgnoreCase) ||
(c.Character != null && c.Character.Name.Equals(playerName, StringComparison.OrdinalIgnoreCase)));
KickClient(client, reason);
}
@@ -2246,11 +2239,9 @@ namespace Barotrauma.Networking
public override void BanPlayer(string playerName, string reason, bool range = false, TimeSpan? duration = null)
{
playerName = playerName.ToLowerInvariant();
Client client = connectedClients.Find(c =>
c.Name.ToLowerInvariant() == playerName ||
(c.Character != null && c.Character.Name.ToLowerInvariant() == playerName));
c.Name.Equals(playerName, StringComparison.OrdinalIgnoreCase) ||
(c.Character != null && c.Character.Name.Equals(playerName, StringComparison.OrdinalIgnoreCase)));
if (client == null)
{
@@ -2284,7 +2275,7 @@ namespace Barotrauma.Networking
ip = lidgrenConn.IPEndPoint.Address.IsIPv4MappedToIPv6 ?
lidgrenConn.IPEndPoint.Address.MapToIPv4NoThrow().ToString() :
lidgrenConn.IPEndPoint.Address.ToString();
if (range) { ip = serverSettings.BanList.ToRange(ip); }
if (range) { ip = BanList.ToRange(ip); }
}
serverSettings.BanList.BanPlayer(client.Name, ip, reason, duration);
@@ -2625,8 +2616,8 @@ namespace Barotrauma.Networking
public void SendOrderChatMessage(OrderChatMessage message)
{
if (message.Sender == null || message.Sender.SpeechImpediment >= 100.0f) return;
ChatMessageType messageType = ChatMessage.CanUseRadio(message.Sender) ? ChatMessageType.Radio : ChatMessageType.Default;
if (message.Sender == null || message.Sender.SpeechImpediment >= 100.0f) { return; }
//ChatMessageType messageType = ChatMessage.CanUseRadio(message.Sender) ? ChatMessageType.Radio : ChatMessageType.Default;
//check which clients can receive the message and apply distance effects
foreach (Client client in ConnectedClients)
@@ -2636,13 +2627,8 @@ namespace Barotrauma.Networking
if (message.Sender != null &&
client.Character != null && !client.Character.IsDead)
{
if (message.Sender != client.Character)
{
modifiedMessage = ChatMessage.ApplyDistanceEffect(message.Text, messageType, message.Sender, client.Character);
}
//too far to hear the msg -> don't send
if (string.IsNullOrWhiteSpace(modifiedMessage)) continue;
if (!client.Character.CanHearCharacter(message.Sender)) { continue; }
}
SendDirectChatMessage(new OrderChatMessage(message.Order, message.OrderOption, message.TargetEntity, message.TargetCharacter, message.Sender), client);
@@ -2924,13 +2910,13 @@ namespace Barotrauma.Networking
{
string jobIdentifier = message.ReadString();
int variant = message.ReadByte();
if (JobPrefab.List.TryGetValue(jobIdentifier, out JobPrefab jobPrefab))
if (JobPrefab.Prefabs.ContainsKey(jobIdentifier))
{
jobPreferences.Add(new Pair<JobPrefab, int>(jobPrefab, variant));
jobPreferences.Add(new Pair<JobPrefab, int>(JobPrefab.Prefabs[jobIdentifier], variant));
}
}
sender.CharacterInfo = new CharacterInfo(Character.HumanSpeciesName, sender.Name);
sender.CharacterInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, sender.Name);
sender.CharacterInfo.RecreateHead(headSpriteId, race, gender, hairIndex, beardIndex, moustacheIndex, faceAttachmentIndex);
//if the client didn't provide job preferences, we'll use the preferences that are randomly assigned in the Client constructor
@@ -2943,7 +2929,7 @@ namespace Barotrauma.Networking
public void AssignJobs(List<Client> unassigned)
{
var jobList = JobPrefab.List.Values.ToList();
var jobList = JobPrefab.Prefabs.ToList();
unassigned = new List<Client>(unassigned);
unassigned = unassigned.OrderBy(sp => Rand.Int(int.MaxValue)).ToList();
@@ -3118,7 +3104,7 @@ namespace Barotrauma.Networking
public void AssignBotJobs(List<CharacterInfo> bots, Character.TeamType teamID)
{
Dictionary<JobPrefab, int> assignedPlayerCount = new Dictionary<JobPrefab, int>();
foreach (JobPrefab jp in JobPrefab.List.Values)
foreach (JobPrefab jp in JobPrefab.Prefabs)
{
assignedPlayerCount.Add(jp, 0);
}
@@ -3154,10 +3140,11 @@ namespace Barotrauma.Networking
{
if (unassignedBots.Count == 0) { break; }
JobPrefab jobPrefab = spawnPoint.AssignedJob ?? JobPrefab.List.Values.GetRandom();
JobPrefab jobPrefab = spawnPoint.AssignedJob ?? JobPrefab.Prefabs.GetRandom();
if (assignedPlayerCount[jobPrefab] >= jobPrefab.MaxNumber) { continue; }
unassignedBots[0].Job = new Job(jobPrefab);
var variant = Rand.Range(0, jobPrefab.Variants, Rand.RandSync.Server);
unassignedBots[0].Job = new Job(jobPrefab, variant);
assignedPlayerCount[jobPrefab]++;
unassignedBots.Remove(unassignedBots[0]);
canAssign = true;
@@ -3168,7 +3155,7 @@ namespace Barotrauma.Networking
foreach (CharacterInfo c in unassignedBots)
{
//find all jobs that are still available
var remainingJobs = JobPrefab.List.Values.Where(jp => assignedPlayerCount[jp] < jp.MaxNumber);
var remainingJobs = JobPrefab.Prefabs.Where(jp => assignedPlayerCount[jp] < jp.MaxNumber);
//all jobs taken, give a random job
if (remainingJobs.Count() == 0)
{
@@ -3178,7 +3165,9 @@ namespace Barotrauma.Networking
}
else //some jobs still left, choose one of them by random
{
c.Job = new Job(remainingJobs.GetRandom());
var job = remainingJobs.GetRandom();
var variant = Rand.Range(0, job.Variants);
c.Job = new Job(job, variant);
assignedPlayerCount[c.Job.Prefab]++;
}
}
@@ -3259,18 +3248,6 @@ namespace Barotrauma.Networking
if (GameMain.NetLobbyScreen.SelectedShuttle != null) { serverSettings.SelectedShuttle = GameMain.NetLobbyScreen.SelectedShuttle.Name; }
serverSettings.SaveSettings();
if (registeredToMaster)
{
if (restClient != null)
{
var request = new RestRequest("masterserver2.php", Method.GET);
request.AddParameter("action", "removeserver");
request.AddParameter("serverport", Port);
restClient.Execute(request);
restClient = null;
}
}
if (serverSettings.SaveServerLogs)
{
Log("Shutting down the server...", ServerLog.MessageType.ServerMessage);
@@ -20,6 +20,11 @@ namespace Barotrauma.Networking
get { return createTime; }
}
public void ResetCreateTime()
{
createTime = Timing.TotalTime;
}
public ServerEntityEvent(IServerSerializable serializableEntity, UInt16 id)
: base(serializableEntity, id)
{
@@ -90,6 +95,8 @@ namespace Barotrauma.Networking
private UInt16 ID;
private GameServer server;
private double lastEventCountHighWarning;
public ServerEntityEventManager(GameServer server)
{
@@ -125,16 +132,14 @@ namespace Barotrauma.Networking
var newEvent = new ServerEntityEvent(entity, (UInt16)(ID + 1));
if (extraData != null) newEvent.SetData(extraData);
bool inGameClientsPresent = server.ConnectedClients.Count(c => c.InGame) > 0;
//remove old events that have been sent to all clients, they are redundant now
// keep at least one event in the list (lastSentToAll == e.ID) so we can use it to keep track of the latest ID
// and events less than 15 seconds old to give disconnected clients a bit of time to reconnect without getting desynced
events.RemoveAll(e => (NetIdUtils.IdMoreRecent(lastSentToAll, e.ID) || !inGameClientsPresent) && e.CreateTime < Timing.TotalTime - 15.0f);
//remove events that have been sent to all clients, they are redundant now
//keep at least one event in the list (lastSentToAll == e.ID) so we can use it to keep track of the latest ID
events.RemoveAll(e => NetIdUtils.IdMoreRecent(lastSentToAll, e.ID));
if (server.ConnectedClients.Count(c => c.InGame) == 0 && events.Count > 1)
{
events.RemoveRange(0, events.Count - 1);
}
for (int i = events.Count - 1; i >= 0; i--)
{
//we already have an identical event that's waiting to be sent
@@ -197,12 +202,13 @@ namespace Barotrauma.Networking
bufferedEvent.IsProcessed = true;
}
var inGameClients = clients.FindAll(c => c.InGame && !c.NeedsMidRoundSync);
if (inGameClients.Count > 0)
{
lastSentToAnyone = inGameClients[0].LastRecvEntityEventID;
lastSentToAll = inGameClients[0].LastRecvEntityEventID;
if (server.OwnerConnection != null)
{
var owner = clients.Find(c => c.Connection == server.OwnerConnection);
@@ -222,6 +228,7 @@ namespace Barotrauma.Networking
{
lastWarningTime = Timing.TotalTime;
GameServer.Log("WARNING: ServerEntityEventManager is lagging behind! Last sent id: " + lastSentToAnyone.ToString() + ", latest create id: " + ID.ToString(), ServerLog.MessageType.ServerMessage);
events.ForEach(e => e.ResetCreateTime());
//TODO: reset clients if this happens, maybe do it if a majority are behind rather than all of them?
}
@@ -236,16 +243,16 @@ namespace Barotrauma.Networking
// in which case we'll wait until the timeout runs out before kicking the client
List<Client> toKick = inGameClients.FindAll(c =>
NetIdUtils.IdMoreRecent((UInt16)(lastSentToAll + 1), c.LastRecvEntityEventID) &&
(firstEventToResend.CreateTime > c.MidRoundSyncTimeOut || lastSentToAnyoneTime > c.MidRoundSyncTimeOut));
(firstEventToResend.CreateTime > c.MidRoundSyncTimeOut || lastSentToAnyoneTime > c.MidRoundSyncTimeOut || Timing.TotalTime > c.MidRoundSyncTimeOut + 10.0));
toKick.ForEach(c =>
{
DebugConsole.NewMessage(c.Name + " was kicked due to excessive desync (expected old event " + (c.LastRecvEntityEventID + 1).ToString() + ")", Color.Red);
GameServer.Log("Disconnecting client " + c.Name + " due to excessive desync (expected old event "
GameServer.Log("Disconnecting client " + c.Name + " due to excessive desync (expected old event "
+ (c.LastRecvEntityEventID + 1).ToString() +
" (created " + (Timing.TotalTime - firstEventToResend.CreateTime).ToString("0.##") + " s ago, " +
(lastSentToAnyoneTime - firstEventToResend.CreateTime).ToString("0.##") + " s older than last event sent to anyone)" +
" Events queued: " + events.Count + ", last sent to all: " + lastSentToAll, ServerLog.MessageType.Error);
server.DisconnectClient(c, "", "ServerMessage.ExcessiveDesyncOldEvent");
server.DisconnectClient(c, "", DisconnectReason.ExcessiveDesyncOldEvent + "/ServerMessage.ExcessiveDesyncOldEvent");
}
);
}
@@ -259,19 +266,19 @@ namespace Barotrauma.Networking
{
DebugConsole.NewMessage(c.Name + " was kicked due to excessive desync (expected removed event " + (c.LastRecvEntityEventID + 1).ToString() + ", last available is " + events[0].ID.ToString() + ")", Color.Red);
GameServer.Log("Disconnecting client " + c.Name + " due to excessive desync (expected removed event " + (c.LastRecvEntityEventID + 1).ToString() + ", last available is " + events[0].ID.ToString() + ")", ServerLog.MessageType.Error);
server.DisconnectClient(c, "", "ServerMessage.ExcessiveDesyncRemovedEvent");
server.DisconnectClient(c, "", DisconnectReason.ExcessiveDesyncRemovedEvent + "/ServerMessage.ExcessiveDesyncRemovedEvent");
});
}
}
var timedOutClients = clients.FindAll(c => c.InGame && c.NeedsMidRoundSync && Timing.TotalTime > c.MidRoundSyncTimeOut);
var timedOutClients = clients.FindAll(c => c.Connection != GameMain.Server.OwnerConnection && c.InGame && c.NeedsMidRoundSync && Timing.TotalTime > c.MidRoundSyncTimeOut);
foreach (Client timedOutClient in timedOutClients)
{
GameServer.Log("Disconnecting client " + timedOutClient.Name + ". Syncing the client with the server took too long.", ServerLog.MessageType.Error);
GameMain.Server.DisconnectClient(timedOutClient, "", "ServerMessage.SyncTimeout");
GameMain.Server.DisconnectClient(timedOutClient, "", DisconnectReason.SyncTimeout + "/ServerMessage.SyncTimeout");
}
bufferedEvents.RemoveAll(b => b.IsProcessed);
bufferedEvents.RemoveAll(b => b.IsProcessed);
}
private void BufferEvent(BufferedEvent bufferedEvent)
@@ -312,11 +319,11 @@ namespace Barotrauma.Networking
List<NetEntityEvent> eventsToSync = null;
if (client.NeedsMidRoundSync)
{
eventsToSync = GetEventsToSync(client, uniqueEvents);
eventsToSync = GetEventsToSync(client);
}
else
{
eventsToSync = GetEventsToSync(client, events);
eventsToSync = GetEventsToSync(client);
}
if (eventsToSync.Count == 0)
@@ -326,9 +333,10 @@ namespace Barotrauma.Networking
}
//too many events for one packet
if (eventsToSync.Count > 200)
//(normal right after a round has just started, don't show a warning if it's been less than 10 seconds)
if (eventsToSync.Count > 200 && GameMain.GameSession != null && Timing.TotalTime > GameMain.GameSession.RoundStartTime + 10.0)
{
if (eventsToSync.Count > 200 && !client.NeedsMidRoundSync)
if (eventsToSync.Count > 200 && !client.NeedsMidRoundSync && Timing.TotalTime > lastEventCountHighWarning + 2.0)
{
Color color = eventsToSync.Count > 500 ? Color.Red : Color.Orange;
if (eventsToSync.Count < 300) { color = Color.Yellow; }
@@ -350,6 +358,7 @@ namespace Barotrauma.Networking
GameServer.Log(warningMsg, ServerLog.MessageType.Error);
}
DebugConsole.NewMessage(warningMsg, color);
lastEventCountHighWarning = Timing.TotalTime;
}
}
@@ -377,13 +386,13 @@ namespace Barotrauma.Networking
/// <summary>
/// Returns a list of events that should be sent to the client from the eventList
/// </summary>
/// <param name="client"></param>
/// <param name="eventList"></param>
/// <returns></returns>
private List<NetEntityEvent> GetEventsToSync(Client client, List<ServerEntityEvent> eventList)
private List<NetEntityEvent> GetEventsToSync(Client client)
{
List<NetEntityEvent> eventsToSync = new List<NetEntityEvent>();
if (eventList.Count == 0) return eventsToSync;
var eventList = client.NeedsMidRoundSync ? uniqueEvents : events;
if (eventList.Count == 0) { return eventsToSync; }
//find the index of the first event the client hasn't received
int startIndex = eventList.Count;
@@ -406,7 +415,18 @@ namespace Barotrauma.Networking
continue;
}
eventsToSync.AddRange(eventList.GetRange(i, eventList.Count - i));
if (client.NeedsMidRoundSync)
{
if (i <= client.UnreceivedEntityEventCount)
{
eventsToSync.AddRange(eventList.GetRange(i, client.UnreceivedEntityEventCount - i));
}
}
else
{
eventsToSync.AddRange(eventList.GetRange(i, eventList.Count - i));
}
break;
}
@@ -3,19 +3,16 @@ using System.Collections.Generic;
using System.Net;
using System.Linq;
using Lidgren.Network;
using Facepunch.Steamworks;
namespace Barotrauma.Networking
{
class LidgrenServerPeer : ServerPeer
{
private ServerSettings serverSettings;
private readonly ServerSettings serverSettings;
private NetPeerConfiguration netPeerConfiguration;
private NetServer netServer;
private Facepunch.Steamworks.Server steamServer;
private class PendingClient
{
public string Name;
@@ -37,16 +34,16 @@ namespace Barotrauma.Networking
Retries = 0;
SteamID = null;
PasswordSalt = null;
UpdateTime = Timing.TotalTime+Timing.Step*3.0;
UpdateTime = Timing.TotalTime + Timing.Step * 3.0;
TimeOut = NetworkConnection.TimeoutThreshold;
AuthSessionStarted = false;
}
}
private List<LidgrenConnection> connectedClients;
private List<PendingClient> pendingClients;
private readonly List<LidgrenConnection> connectedClients;
private readonly List<PendingClient> pendingClients;
private List<NetIncomingMessage> incomingLidgrenMessages;
private readonly List<NetIncomingMessage> incomingLidgrenMessages;
public LidgrenServerPeer(int? ownKey, ServerSettings settings)
{
@@ -59,8 +56,6 @@ namespace Barotrauma.Networking
incomingLidgrenMessages = new List<NetIncomingMessage>();
steamServer = null;
ownerKey = ownKey;
}
@@ -72,7 +67,7 @@ namespace Barotrauma.Networking
{
AcceptIncomingConnections = true,
AutoExpandMTU = false,
MaximumConnections = serverSettings.MaxPlayers * 2,
MaximumConnections = NetConfig.MaxPlayers * 2,
EnableUPnP = serverSettings.EnableUPnP,
Port = serverSettings.Port
};
@@ -85,7 +80,7 @@ namespace Barotrauma.Networking
netPeerConfiguration.EnableMessageType(NetIncomingMessageType.ConnectionApproval);
netServer = new NetServer(netPeerConfiguration);
netServer.Start();
if (serverSettings.EnableUPnP)
@@ -119,11 +114,7 @@ namespace Barotrauma.Networking
netServer = null;
if (steamServer != null)
{
steamServer.Auth.OnAuthChange = null;
}
steamServer = null;
Steamworks.SteamServer.OnValidateAuthTicketResponse -= OnAuthChange;
OnShutdown?.Invoke();
}
@@ -189,10 +180,9 @@ namespace Barotrauma.Networking
if (netServer == null) { return; }
netServer.UPnP.ForwardPort(netPeerConfiguration.Port, "barotrauma");
if (Steam.SteamManager.USE_STEAM)
{
netServer.UPnP.ForwardPort(serverSettings.QueryPort, "barotrauma");
}
#if USE_STEAM
netServer.UPnP.ForwardPort(serverSettings.QueryPort, "barotrauma");
#endif
}
private bool DiscoveringUPnP()
@@ -217,11 +207,10 @@ namespace Barotrauma.Networking
return;
}
if (serverSettings.BanList.IsBanned(inc.SenderConnection.RemoteEndPoint.Address, 0))
if (serverSettings.BanList.IsBanned(inc.SenderConnection.RemoteEndPoint.Address, 0, out string banReason))
{
//IP banned: deny immediately
//TODO: use TextManager
inc.SenderConnection.Deny(DisconnectReason.Banned.ToString()+"/ IP banned");
inc.SenderConnection.Deny(DisconnectReason.Banned.ToString() + "/ " + banReason);
return;
}
@@ -267,9 +256,9 @@ namespace Barotrauma.Networking
return;
}
if (pendingClient != null) { pendingClients.Remove(pendingClient); }
if (serverSettings.BanList.IsBanned(conn.IPEndPoint.Address, conn.SteamID))
if (serverSettings.BanList.IsBanned(conn.IPEndPoint.Address, conn.SteamID, out string banReason))
{
Disconnect(conn, DisconnectReason.Banned.ToString()+"/ Received data message from banned client");
Disconnect(conn, DisconnectReason.Banned.ToString() + "/ " + banReason);
return;
}
UInt16 length = inc.ReadUInt16();
@@ -427,19 +416,20 @@ namespace Barotrauma.Networking
#if DEBUG
requireSteamAuth = false;
#endif
//steam auth cannot be done (SteamManager not initialized or no ticket given),
//but it's not required either -> let the client join without auth
if ((!Steam.SteamManager.IsInitialized || ticket.Length == 0) &&
if ((!Steam.SteamManager.IsInitialized || (ticket?.Length??0) == 0) &&
!requireSteamAuth)
{
pendingClient.Name = name;
pendingClient.OwnerKey = ownKey;
pendingClient.InitializationStep = ConnectionInitialization.Success;
pendingClient.InitializationStep = ConnectionInitialization.ContentPackageOrder;
}
else
{
ServerAuth.StartAuthSessionResult authSessionStartState = Steam.SteamManager.StartAuthSession(ticket, steamId);
if (authSessionStartState != ServerAuth.StartAuthSessionResult.OK)
Steamworks.BeginAuthResult authSessionStartState = Steam.SteamManager.StartAuthSession(ticket, steamId);
if (authSessionStartState != Steamworks.BeginAuthResult.OK)
{
RemovePendingClient(pendingClient, DisconnectReason.SteamAuthenticationFailed, "Steam auth session failed to start: " + authSessionStartState.ToString());
return;
@@ -470,13 +460,12 @@ namespace Barotrauma.Networking
}
if (serverSettings.IsPasswordCorrect(incPassword, pendingClient.PasswordSalt.Value))
{
pendingClient.InitializationStep = ConnectionInitialization.Success;
pendingClient.InitializationStep = ConnectionInitialization.ContentPackageOrder;
}
else
{
pendingClient.Retries++;
if (pendingClient.Retries >= 3)
if (serverSettings.BanAfterWrongPassword && pendingClient.Retries > serverSettings.MaxPasswordRetriesBeforeBan)
{
string banMsg = "Failed to enter correct password too many times";
if (pendingClient.SteamID != null)
@@ -490,6 +479,10 @@ namespace Barotrauma.Networking
}
pendingClient.UpdateTime = Timing.TotalTime;
break;
case ConnectionInitialization.ContentPackageOrder:
pendingClient.InitializationStep = ConnectionInitialization.Success;
pendingClient.UpdateTime = Timing.TotalTime;
break;
}
}
@@ -498,9 +491,9 @@ namespace Barotrauma.Networking
{
if (netServer == null) { return; }
if (serverSettings.BanList.IsBanned(pendingClient.Connection.RemoteEndPoint.Address, pendingClient.SteamID ?? 0))
if (serverSettings.BanList.IsBanned(pendingClient.Connection.RemoteEndPoint.Address, pendingClient.SteamID ?? 0, out string banReason))
{
RemovePendingClient(pendingClient, DisconnectReason.Banned, "");
RemovePendingClient(pendingClient, DisconnectReason.Banned, banReason);
return;
}
@@ -547,6 +540,14 @@ namespace Barotrauma.Networking
outMsg.Write((byte)pendingClient.InitializationStep);
switch (pendingClient.InitializationStep)
{
case ConnectionInitialization.ContentPackageOrder:
var mpContentPackages = GameMain.SelectedPackages.Where(cp => cp.HasMultiplayerIncompatibleContent).ToList();
outMsg.WriteVariableInt32(mpContentPackages.Count);
for (int i = 0; i < mpContentPackages.Count; i++)
{
outMsg.Write(mpContentPackages[i].MD5hash.Hash);
}
break;
case ConnectionInitialization.Password:
outMsg.Write(pendingClient.PasswordSalt == null); outMsg.WritePadBits();
if (pendingClient.PasswordSalt == null)
@@ -571,7 +572,7 @@ namespace Barotrauma.Networking
{
DebugConsole.NewMessage("Failed to send initialization step " + pendingClient.InitializationStep.ToString() + " to pending client: " + result.ToString(), Microsoft.Xna.Framework.Color.Yellow);
}
//DebugConsole.NewMessage("sent update to pending client: "+result);
//DebugConsole.NewMessage("sent update to pending client: " + pendingClient.InitializationStep);
}
private void RemovePendingClient(PendingClient pendingClient, DisconnectReason reason, string msg)
@@ -593,14 +594,12 @@ namespace Barotrauma.Networking
}
}
public override void InitializeSteamServerCallbacks(Server steamSrvr)
public override void InitializeSteamServerCallbacks()
{
steamServer = steamSrvr;
steamServer.Auth.OnAuthChange = OnAuthChange;
Steamworks.SteamServer.OnValidateAuthTicketResponse += OnAuthChange;
}
private void OnAuthChange(ulong steamID, ulong ownerID, ServerAuth.Status status)
private void OnAuthChange(Steamworks.SteamId steamID, Steamworks.SteamId ownerID, Steamworks.AuthResponse status)
{
if (netServer == null) { return; }
@@ -609,7 +608,7 @@ namespace Barotrauma.Networking
if (pendingClient == null)
{
if (status != ServerAuth.Status.OK)
if (status != Steamworks.AuthResponse.OK)
{
LidgrenConnection connection = connectedClients.Find(c => c.SteamID == steamID);
if (connection != null)
@@ -620,15 +619,15 @@ namespace Barotrauma.Networking
return;
}
if (serverSettings.BanList.IsBanned(pendingClient.Connection.RemoteEndPoint.Address, steamID))
if (serverSettings.BanList.IsBanned(pendingClient.Connection.RemoteEndPoint.Address, steamID, out string banReason))
{
RemovePendingClient(pendingClient, DisconnectReason.Banned, "SteamID banned");
RemovePendingClient(pendingClient, DisconnectReason.Banned, banReason);
return;
}
if (status == ServerAuth.Status.OK)
if (status == Steamworks.AuthResponse.OK)
{
pendingClient.InitializationStep = serverSettings.HasPassword ? ConnectionInitialization.Password : ConnectionInitialization.Success;
pendingClient.InitializationStep = serverSettings.HasPassword ? ConnectionInitialization.Password : ConnectionInitialization.ContentPackageOrder;
pendingClient.UpdateTime = Timing.TotalTime;
}
else
@@ -1,5 +1,4 @@
using Facepunch.Steamworks;
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@@ -44,7 +43,7 @@ namespace Barotrauma.Networking
public NetworkConnection OwnerConnection { get; protected set; }
public abstract void InitializeSteamServerCallbacks(Facepunch.Steamworks.Server steamSrvr);
public abstract void InitializeSteamServerCallbacks();
public abstract void Start();
public abstract void Close(string msg = null);
@@ -3,20 +3,15 @@ using System.Collections.Generic;
using System.Net;
using System.Linq;
using System.Threading;
using Lidgren.Network;
using Facepunch.Steamworks;
namespace Barotrauma.Networking
{
class SteamP2PServerPeer : ServerPeer
{
private bool started;
private ServerSettings serverSettings;
private NetPeerConfiguration netPeerConfiguration;
private NetServer netServer;
private NetConnection netConnection;
public UInt64 OwnerSteamID
{
get;
@@ -54,52 +49,37 @@ namespace Barotrauma.Networking
private List<SteamP2PConnection> connectedClients;
private List<PendingClient> pendingClients;
private List<NetIncomingMessage> incomingLidgrenMessages;
public SteamP2PServerPeer(UInt64 steamId, ServerSettings settings)
{
serverSettings = settings;
netServer = null;
connectedClients = new List<SteamP2PConnection>();
pendingClients = new List<PendingClient>();
incomingLidgrenMessages = new List<NetIncomingMessage>();
ownerKey = null;
OwnerSteamID = steamId;
started = false;
}
public override void Start()
{
if (netServer != null) { return; }
IWriteMessage outMsg = new WriteOnlyMessage();
outMsg.Write(OwnerSteamID);
outMsg.Write((byte)DeliveryMethod.Reliable);
outMsg.Write((byte)(PacketHeader.IsConnectionInitializationStep | PacketHeader.IsServerMessage));
netPeerConfiguration = new NetPeerConfiguration("barotrauma")
{
AcceptIncomingConnections = true,
AutoExpandMTU = false,
MaximumConnections = 1, //only allow owner to connect
EnableUPnP = false,
Port = Steam.SteamManager.STEAMP2P_OWNER_PORT
};
byte[] msgToSend = (byte[])outMsg.Buffer.Clone();
Array.Resize(ref msgToSend, outMsg.LengthBytes);
ChildServerRelay.Write(msgToSend);
netPeerConfiguration.DisableMessageType(NetIncomingMessageType.DebugMessage |
NetIncomingMessageType.WarningMessage | NetIncomingMessageType.Receipt |
NetIncomingMessageType.ErrorMessage | NetIncomingMessageType.Error |
NetIncomingMessageType.UnconnectedData);
netPeerConfiguration.EnableMessageType(NetIncomingMessageType.ConnectionApproval);
netServer = new NetServer(netPeerConfiguration);
netServer.Start();
started = true;
}
public override void Close(string msg = null)
{
if (netServer == null) { return; }
if (!started) { return; }
if (OwnerConnection != null) OwnerConnection.Status = NetworkConnectionStatus.Disconnected;
@@ -113,19 +93,17 @@ namespace Barotrauma.Networking
Disconnect(connectedClients[i], msg ?? DisconnectReason.ServerShutdown.ToString());
}
netServer.Shutdown(msg ?? DisconnectReason.ServerShutdown.ToString());
pendingClients.Clear();
connectedClients.Clear();
netServer = null;
ChildServerRelay.ShutDown();
OnShutdown?.Invoke();
}
public override void Update(float deltaTime)
{
if (netServer == null) { return; }
if (!started) { return; }
if (OnOwnerDetermined != null && OwnerConnection != null)
{
@@ -133,8 +111,6 @@ namespace Barotrauma.Networking
OnOwnerDetermined = null;
}
netServer.ReadMessages(incomingLidgrenMessages);
//backwards for loop so we can remove elements while iterating
for (int i = connectedClients.Count - 1; i >= 0; i--)
{
@@ -145,27 +121,13 @@ namespace Barotrauma.Networking
}
}
//process incoming connections first
foreach (NetIncomingMessage inc in incomingLidgrenMessages.Where(m => m.MessageType == NetIncomingMessageType.ConnectionApproval))
{
HandleConnection(inc);
}
try
{
//after processing connections, go ahead with the rest of the messages
foreach (NetIncomingMessage inc in incomingLidgrenMessages.Where(m => m.MessageType != NetIncomingMessageType.ConnectionApproval))
while (ChildServerRelay.Read(out byte[] incBuf))
{
switch (inc.MessageType)
{
case NetIncomingMessageType.Data:
HandleDataMessage(inc);
break;
case NetIncomingMessageType.StatusChanged:
HandleStatusChanged(inc);
break;
}
IReadMessage inc = new ReadOnlyMessage(incBuf, false, 0, incBuf.Length, OwnerConnection);
HandleDataMessage(inc);
}
}
@@ -186,36 +148,11 @@ namespace Barotrauma.Networking
UpdatePendingClient(pendingClient);
if (i >= pendingClients.Count || pendingClients[i] != pendingClient) { i--; }
}
incomingLidgrenMessages.Clear();
}
private void HandleConnection(NetIncomingMessage inc)
private void HandleDataMessage(IReadMessage inc)
{
if (netServer == null) { return; }
if (netConnection != null && inc.SenderConnection != netConnection)
{
inc.SenderConnection.Deny(DisconnectReason.SessionTaken.ToString()+"/ Owner is already connected");
return;
}
if (IPAddress.IsLoopback(inc.SenderConnection.RemoteEndPoint.Address.MapToIPv4NoThrow()))
{
inc.SenderConnection.Approve();
netConnection = inc.SenderConnection;
return;
}
inc.SenderConnection.Deny(DisconnectReason.Kicked.ToString()+"/ Incoming connection is not loopback");
}
private void HandleDataMessage(NetIncomingMessage inc)
{
if (netServer == null) { return; }
if (inc.SenderConnection != netConnection) { return; }
if (!started) { return; }
UInt64 senderSteamId = inc.ReadUInt64();
@@ -240,15 +177,15 @@ namespace Barotrauma.Networking
pendingClient?.Heartbeat();
connectedClient?.Heartbeat();
if (serverSettings.BanList.IsBanned(senderSteamId))
if (serverSettings.BanList.IsBanned(senderSteamId, out string banReason))
{
if (pendingClient != null)
{
RemovePendingClient(pendingClient, DisconnectReason.Banned, "Banned");
RemovePendingClient(pendingClient, DisconnectReason.Banned, banReason);
}
else if (connectedClient != null)
{
Disconnect(connectedClient, DisconnectReason.Banned.ToString() + "/ Banned");
Disconnect(connectedClient, DisconnectReason.Banned.ToString() + "/ "+ banReason);
}
return;
}
@@ -275,7 +212,7 @@ namespace Barotrauma.Networking
{
if (pendingClient != null)
{
ReadConnectionInitializationStep(pendingClient, new ReadOnlyMessage(inc.Data, false, inc.PositionInBytes, inc.LengthBytes - inc.PositionInBytes, null));
ReadConnectionInitializationStep(pendingClient, new ReadOnlyMessage(inc.Buffer, false, inc.BytePosition, inc.LengthBytes - inc.BytePosition, null));
}
else
{
@@ -290,7 +227,7 @@ namespace Barotrauma.Networking
{
UInt16 length = inc.ReadUInt16();
IReadMessage msg = new ReadOnlyMessage(inc.Data, isCompressed, inc.PositionInBytes, length, connectedClient);
IReadMessage msg = new ReadOnlyMessage(inc.Buffer, isCompressed, inc.BytePosition, length, connectedClient);
OnMessageReceived?.Invoke(connectedClient, msg);
}
}
@@ -330,41 +267,15 @@ namespace Barotrauma.Networking
{
UInt16 length = inc.ReadUInt16();
IReadMessage msg = new ReadOnlyMessage(inc.Data, isCompressed, inc.PositionInBytes, length, OwnerConnection);
IReadMessage msg = new ReadOnlyMessage(inc.Buffer, isCompressed, inc.BytePosition, length, OwnerConnection);
OnMessageReceived?.Invoke(OwnerConnection, msg);
}
}
}
private void HandleStatusChanged(NetIncomingMessage inc)
{
if (netServer == null) { return; }
DebugConsole.NewMessage(inc.SenderConnection.Status.ToString());
switch (inc.SenderConnection.Status)
{
case NetConnectionStatus.Connected:
NetOutgoingMessage outMsg = netServer.CreateMessage();
outMsg.Write(OwnerSteamID);
outMsg.Write((byte)(PacketHeader.IsConnectionInitializationStep | PacketHeader.IsServerMessage));
NetSendResult result = netServer.SendMessage(outMsg, netConnection, NetDeliveryMethod.ReliableUnordered);
if (result != NetSendResult.Sent && result != NetSendResult.Queued)
{
DebugConsole.NewMessage("Failed to send connection confirmation message to owner: " + result.ToString(), Microsoft.Xna.Framework.Color.Yellow);
}
break;
case NetConnectionStatus.Disconnected:
DebugConsole.NewMessage("Owner disconnected: closing the server...");
GameServer.Log("Owner disconnected: closing the server...", ServerLog.MessageType.ServerMessage);
Close(DisconnectReason.ServerShutdown.ToString() + "/ Owner disconnected");
break;
}
}
private void ReadConnectionInitializationStep(PendingClient pendingClient, IReadMessage inc)
{
if (netServer == null) { return; }
if (!started) { return; }
pendingClient.TimeOut = NetworkConnection.TimeoutThreshold;
@@ -463,7 +374,7 @@ namespace Barotrauma.Networking
if (!pendingClient.AuthSessionStarted)
{
pendingClient.InitializationStep = serverSettings.HasPassword ? ConnectionInitialization.Password: ConnectionInitialization.Success;
pendingClient.InitializationStep = serverSettings.HasPassword ? ConnectionInitialization.Password : ConnectionInitialization.ContentPackageOrder;
pendingClient.Name = name;
pendingClient.AuthSessionStarted = true;
@@ -479,13 +390,12 @@ namespace Barotrauma.Networking
}
if (serverSettings.IsPasswordCorrect(incPassword, pendingClient.PasswordSalt.Value))
{
pendingClient.InitializationStep = ConnectionInitialization.Success;
pendingClient.InitializationStep = ConnectionInitialization.ContentPackageOrder;
}
else
{
pendingClient.Retries++;
if (pendingClient.Retries >= 3)
if (serverSettings.BanAfterWrongPassword && pendingClient.Retries > serverSettings.MaxPasswordRetriesBeforeBan)
{
string banMsg = "Failed to enter correct password too many times";
serverSettings.BanList.BanPlayer(pendingClient.Name, pendingClient.SteamID, banMsg, null);
@@ -496,17 +406,21 @@ namespace Barotrauma.Networking
}
pendingClient.UpdateTime = Timing.TotalTime;
break;
case ConnectionInitialization.ContentPackageOrder:
pendingClient.InitializationStep = ConnectionInitialization.Success;
pendingClient.UpdateTime = Timing.TotalTime;
break;
}
}
private void UpdatePendingClient(PendingClient pendingClient)
{
if (netServer == null) { return; }
if (!started) { return; }
if (serverSettings.BanList.IsBanned(pendingClient.SteamID))
if (serverSettings.BanList.IsBanned(pendingClient.SteamID, out string banReason))
{
RemovePendingClient(pendingClient, DisconnectReason.Banned, "Initialization interrupted by ban");
RemovePendingClient(pendingClient, DisconnectReason.Banned, banReason);
return;
}
@@ -537,18 +451,27 @@ namespace Barotrauma.Networking
if (Timing.TotalTime < pendingClient.UpdateTime) { return; }
pendingClient.UpdateTime = Timing.TotalTime + 1.0;
NetOutgoingMessage outMsg = netServer.CreateMessage();
IWriteMessage outMsg = new WriteOnlyMessage();
outMsg.Write(pendingClient.SteamID);
outMsg.Write((byte)DeliveryMethod.Reliable);
outMsg.Write((byte)(PacketHeader.IsConnectionInitializationStep |
PacketHeader.IsServerMessage));
outMsg.Write((byte)pendingClient.InitializationStep);
switch (pendingClient.InitializationStep)
{
case ConnectionInitialization.ContentPackageOrder:
var mpContentPackages = GameMain.SelectedPackages.Where(cp => cp.HasMultiplayerIncompatibleContent).ToList();
outMsg.WriteVariableUInt32((UInt32)mpContentPackages.Count);
for (int i = 0; i < mpContentPackages.Count; i++)
{
outMsg.Write(mpContentPackages[i].MD5hash.Hash);
}
break;
case ConnectionInitialization.Password:
outMsg.Write(pendingClient.PasswordSalt == null); outMsg.WritePadBits();
if (pendingClient.PasswordSalt == null)
{
pendingClient.PasswordSalt = CryptoRandom.Instance.Next();
pendingClient.PasswordSalt = Lidgren.Network.CryptoRandom.Instance.Next();
outMsg.Write(pendingClient.PasswordSalt.Value);
}
else
@@ -558,19 +481,14 @@ namespace Barotrauma.Networking
break;
}
if (netConnection != null)
{
NetSendResult result = netServer.SendMessage(outMsg, netConnection, NetDeliveryMethod.ReliableUnordered);
if (result != NetSendResult.Sent && result != NetSendResult.Queued)
{
DebugConsole.NewMessage("Failed to send initialization step " + pendingClient.InitializationStep.ToString() + " to pending client: " + result.ToString(), Microsoft.Xna.Framework.Color.Yellow);
}
}
byte[] msgToSend = (byte[])outMsg.Buffer.Clone();
Array.Resize(ref msgToSend, outMsg.LengthBytes);
ChildServerRelay.Write(msgToSend);
}
private void RemovePendingClient(PendingClient pendingClient, DisconnectReason reason, string msg)
{
if (netServer == null) { return; }
if (!started) { return; }
if (pendingClients.Contains(pendingClient))
{
@@ -587,14 +505,14 @@ namespace Barotrauma.Networking
}
}
public override void InitializeSteamServerCallbacks(Server steamSrvr)
public override void InitializeSteamServerCallbacks()
{
throw new InvalidOperationException("Called InitializeSteamServerCallbacks on SteamP2PServerPeer!");
}
public override void Send(IWriteMessage msg, NetworkConnection conn, DeliveryMethod deliveryMethod)
{
if (netServer == null) { return; }
if (!started) { return; }
if (!(conn is SteamP2PConnection steamp2pConn)) return;
if (!connectedClients.Contains(steamp2pConn) && conn != OwnerConnection)
@@ -603,60 +521,39 @@ namespace Barotrauma.Networking
return;
}
NetDeliveryMethod lidgrenDeliveryMethod = NetDeliveryMethod.Unreliable;
switch (deliveryMethod)
{
case DeliveryMethod.Unreliable:
lidgrenDeliveryMethod = NetDeliveryMethod.Unreliable;
break;
case DeliveryMethod.Reliable:
lidgrenDeliveryMethod = NetDeliveryMethod.ReliableUnordered;
break;
case DeliveryMethod.ReliableOrdered:
lidgrenDeliveryMethod = NetDeliveryMethod.ReliableOrdered;
break;
}
#if DEBUG
netPeerConfiguration.SimulatedDuplicatesChance = GameMain.Server.SimulatedDuplicatesChance;
netPeerConfiguration.SimulatedMinimumLatency = GameMain.Server.SimulatedMinimumLatency;
netPeerConfiguration.SimulatedRandomLatency = GameMain.Server.SimulatedRandomLatency;
netPeerConfiguration.SimulatedLoss = GameMain.Server.SimulatedLoss;
#endif
NetOutgoingMessage lidgrenMsg = netServer.CreateMessage();
IWriteMessage msgToSend = new WriteOnlyMessage();
byte[] msgData = new byte[msg.LengthBytes];
msg.PrepareForSending(ref msgData, out bool isCompressed, out int length);
lidgrenMsg.Write(conn.SteamID);
lidgrenMsg.Write((byte)((isCompressed ? PacketHeader.IsCompressed : PacketHeader.None) | PacketHeader.IsServerMessage));
lidgrenMsg.Write((UInt16)length);
lidgrenMsg.Write(msgData, 0, length);
msgToSend.Write(conn.SteamID);
msgToSend.Write((byte)deliveryMethod);
msgToSend.Write((byte)((isCompressed ? PacketHeader.IsCompressed : PacketHeader.None) | PacketHeader.IsServerMessage));
msgToSend.Write((UInt16)length);
msgToSend.Write(msgData, 0, length);
NetSendResult result = netServer.SendMessage(lidgrenMsg, netConnection, lidgrenDeliveryMethod);
if (result != NetSendResult.Sent && result != NetSendResult.Queued)
{
DebugConsole.NewMessage("Failed to send message to " + conn.Name + ": " + result.ToString(), Microsoft.Xna.Framework.Color.Yellow);
}
byte[] bufToSend = (byte[])msgToSend.Buffer.Clone();
Array.Resize(ref bufToSend, msgToSend.LengthBytes);
ChildServerRelay.Write(bufToSend);
}
private void SendDisconnectMessage(UInt64 steamId, string msg)
{
if (netServer == null) { return; }
if (!started) { return; }
if (string.IsNullOrWhiteSpace(msg)) { return; }
NetOutgoingMessage lidgrenMsg = netServer.CreateMessage();
lidgrenMsg.Write(steamId);
lidgrenMsg.Write((byte)(PacketHeader.IsDisconnectMessage | PacketHeader.IsServerMessage));
lidgrenMsg.Write(msg);
IWriteMessage msgToSend = new WriteOnlyMessage();
msgToSend.Write(steamId);
msgToSend.Write((byte)DeliveryMethod.Reliable);
msgToSend.Write((byte)(PacketHeader.IsDisconnectMessage | PacketHeader.IsServerMessage));
msgToSend.Write(msg);
NetSendResult result = netServer.SendMessage(lidgrenMsg, netConnection, NetDeliveryMethod.ReliableUnordered);
if (result != NetSendResult.Sent && result != NetSendResult.Queued)
{
DebugConsole.NewMessage("Failed to send disconnect message to " + Steam.SteamManager.SteamIDUInt64ToString(steamId) + ": " + result.ToString(), Microsoft.Xna.Framework.Color.Yellow);
}
byte[] bufToSend = (byte[])msgToSend.Buffer.Clone();
Array.Resize(ref bufToSend, msgToSend.LengthBytes);
ChildServerRelay.Write(bufToSend);
}
private void Disconnect(NetworkConnection conn, string msg, bool sendDisconnectMessage)
{
if (netServer == null) { return; }
if (!started) { return; }
if (!(conn is SteamP2PConnection steamp2pConn)) { return; }
if (connectedClients.Contains(steamp2pConn))
@@ -669,7 +566,7 @@ namespace Barotrauma.Networking
}
else if (steamp2pConn == OwnerConnection)
{
netConnection.Disconnect(msg);
//TODO: fix?
}
}
@@ -43,7 +43,7 @@ namespace Barotrauma.Networking
CharacterInfo botToRespawn = existingBots.Find(b => b.IsDead)?.Info;
if (botToRespawn == null)
{
botToRespawn = new CharacterInfo(Character.HumanSpeciesName);
botToRespawn = new CharacterInfo(CharacterPrefab.HumanSpeciesName);
}
else
{
@@ -222,10 +222,13 @@ namespace Barotrauma.Networking
var clients = GetClientsToRespawn();
foreach (Client c in clients)
{
//get rid of the existing character
c.Character?.DespawnNow();
//all characters are in Team 1 in game modes/missions with only one team.
//if at some point we add a game mode with multiple teams where respawning is possible, this needs to be reworked
c.TeamID = Character.TeamType.Team1;
if (c.CharacterInfo == null) c.CharacterInfo = new CharacterInfo(Character.HumanSpeciesName, c.Name);
if (c.CharacterInfo == null) { c.CharacterInfo = new CharacterInfo(CharacterPrefab.HumanSpeciesName, c.Name); }
}
List<CharacterInfo> characterInfos = clients.Select(c => c.CharacterInfo).ToList();
@@ -255,6 +258,9 @@ namespace Barotrauma.Networking
{
bool bot = i >= clients.Count;
characterInfos[i].CurrentOrder = null;
characterInfos[i].CurrentOrderOption = null;
var character = Character.Create(characterInfos[i], shuttleSpawnPoints[i].WorldPosition, characterInfos[i].Name, !bot, bot);
character.TeamID = Character.TeamType.Team1;
@@ -48,7 +48,7 @@ namespace Barotrauma.Networking
outMsg.Write(ServerMessageText);
outMsg.Write((byte)MaxPlayers);
outMsg.Write(HasPassword);
outMsg.Write(isPublic);
outMsg.Write(IsPublic);
outMsg.WritePadBits();
outMsg.WriteRangedInteger(TickRate, 1, 60);
@@ -175,6 +175,7 @@ namespace Barotrauma.Networking
GameMain.NetworkMember?.KarmaManager?.SaveCustomPreset();
GameMain.NetworkMember?.KarmaManager?.Save();
}
SaveSettings();
GameMain.NetLobbyScreen.LastUpdateID++;
}
}
@@ -183,23 +184,25 @@ namespace Barotrauma.Networking
{
XDocument doc = new XDocument(new XElement("serversettings"));
SerializableProperty.SerializeProperties(this, doc.Root, true);
doc.Root.SetAttributeValue("name", ServerName);
doc.Root.SetAttributeValue("public", isPublic);
doc.Root.SetAttributeValue("public", IsPublic);
doc.Root.SetAttributeValue("port", Port);
if (Steam.SteamManager.USE_STEAM) doc.Root.SetAttributeValue("queryport", QueryPort);
doc.Root.SetAttributeValue("maxplayers", maxPlayers);
#if USE_STEAM
doc.Root.SetAttributeValue("queryport", QueryPort);
#endif
doc.Root.SetAttributeValue("password", password ?? "");
doc.Root.SetAttributeValue("enableupnp", EnableUPnP);
doc.Root.SetAttributeValue("autorestart", autoRestart);
doc.Root.SetAttributeValue("LevelDifficulty", ((int)selectedLevelDifficulty).ToString());
doc.Root.SetAttributeValue("ServerMessage", ServerMessageText);
doc.Root.SetAttributeValue("AllowedRandomMissionTypes", string.Join(",", AllowedRandomMissionTypes));
doc.Root.SetAttributeValue("AllowedClientNameChars", string.Join(",", AllowedClientNameChars.Select(c => c.First + "-" + c.Second)));
doc.Root.SetAttributeValue("ServerMessage", ServerMessageText);
SerializableProperty.SerializeProperties(this, doc.Root, true);
XmlWriterSettings settings = new XmlWriterSettings
{
@@ -318,11 +321,7 @@ namespace Barotrauma.Networking
GameMain.NetLobbyScreen.SetBotSpawnMode(BotSpawnMode);
GameMain.NetLobbyScreen.SetBotCount(BotCount);
List<string> monsterNames = GameMain.Instance.GetFilesOfType(ContentType.Character).ToList();
for (int i = 0; i < monsterNames.Count; i++)
{
monsterNames[i] = Path.GetFileName(Path.GetDirectoryName(monsterNames[i]));
}
List<string> monsterNames = CharacterPrefab.Prefabs.Select(p => p.Identifier).ToList();
MonsterEnabled = new Dictionary<string, bool>();
foreach (string s in monsterNames)
{
@@ -368,7 +367,7 @@ namespace Barotrauma.Networking
if (clientElement.Attribute("preset") == null)
{
string permissionsStr = clientElement.GetAttributeString("permissions", "");
if (permissionsStr.ToLowerInvariant() == "all")
if (permissionsStr.Equals("all", StringComparison.OrdinalIgnoreCase))
{
foreach (ClientPermissions permission in Enum.GetValues(typeof(ClientPermissions)))
{
@@ -385,7 +384,7 @@ namespace Barotrauma.Networking
{
foreach (XElement commandElement in clientElement.Elements())
{
if (commandElement.Name.ToString().ToLowerInvariant() != "command") continue;
if (!commandElement.Name.ToString().Equals("command", StringComparison.OrdinalIgnoreCase)) { continue; }
string commandName = commandElement.GetAttributeString("name", "");
DebugConsole.Command command = DebugConsole.FindCommand(commandName);
@@ -0,0 +1,112 @@
using System.Linq;
namespace Barotrauma.Steam
{
partial class SteamManager
{
#region Server
private static void InitializeProjectSpecific() { isInitialized = true; }
private static void UpdateProjectSpecific(float deltaTime) { }
public static bool CreateServer(Networking.GameServer server, bool isPublic)
{
isInitialized = true;
Steamworks.SteamServerInit options = new Steamworks.SteamServerInit("Barotrauma", "Barotrauma")
{
GamePort = (ushort)server.Port,
QueryPort = (ushort)server.QueryPort,
Secure = false
};
//options.QueryShareGamePort();
Steamworks.SteamServer.Init(AppID, options, false);
if (!Steamworks.SteamServer.IsValid)
{
Steamworks.SteamServer.Shutdown();
DebugConsole.ThrowError("Initializing Steam server failed.");
return false;
}
RefreshServerDetails(server);
server.ServerPeer.InitializeSteamServerCallbacks();
Steamworks.SteamServer.LogOnAnonymous();
return true;
}
public static bool RefreshServerDetails(Networking.GameServer server)
{
if (!isInitialized || !Steamworks.SteamServer.IsValid)
{
return false;
}
var contentPackages = GameMain.Config.SelectedContentPackages.Where(cp => cp.HasMultiplayerIncompatibleContent);
// These server state variables may be changed at any time. Note that there is no longer a mechanism
// to send the player count. The player count is maintained by steam and you should use the player
// creation/authentication functions to maintain your player count.
Steamworks.SteamServer.ServerName = server.ServerName;
Steamworks.SteamServer.MaxPlayers = server.ServerSettings.MaxPlayers;
Steamworks.SteamServer.Passworded = server.ServerSettings.HasPassword;
Steamworks.SteamServer.MapName = GameMain.NetLobbyScreen?.SelectedSub?.DisplayName ?? "";
Steamworks.SteamServer.SetKey("message", GameMain.Server.ServerSettings.ServerMessageText);
Steamworks.SteamServer.SetKey("version", GameMain.Version.ToString());
Steamworks.SteamServer.SetKey("playercount", GameMain.Server.ConnectedClients.Count.ToString());
Steamworks.SteamServer.SetKey("contentpackage", string.Join(",", contentPackages.Select(cp => cp.Name)));
Steamworks.SteamServer.SetKey("contentpackagehash", string.Join(",", contentPackages.Select(cp => cp.MD5hash.Hash)));
Steamworks.SteamServer.SetKey("contentpackageurl", string.Join(",", contentPackages.Select(cp => cp.SteamWorkshopUrl ?? "")));
Steamworks.SteamServer.SetKey("usingwhitelist", (server.ServerSettings.Whitelist != null && server.ServerSettings.Whitelist.Enabled).ToString());
Steamworks.SteamServer.SetKey("modeselectionmode", server.ServerSettings.ModeSelectionMode.ToString());
Steamworks.SteamServer.SetKey("subselectionmode", server.ServerSettings.SubSelectionMode.ToString());
Steamworks.SteamServer.SetKey("voicechatenabled", server.ServerSettings.VoiceChatEnabled.ToString());
Steamworks.SteamServer.SetKey("allowspectating", server.ServerSettings.AllowSpectating.ToString());
Steamworks.SteamServer.SetKey("allowrespawn", server.ServerSettings.AllowRespawn.ToString());
Steamworks.SteamServer.SetKey("traitors", server.ServerSettings.TraitorsEnabled.ToString());
Steamworks.SteamServer.SetKey("gamestarted", server.GameStarted.ToString());
Steamworks.SteamServer.SetKey("gamemode", server.ServerSettings.GameModeIdentifier);
Steamworks.SteamServer.DedicatedServer = true;
return true;
}
public static Steamworks.BeginAuthResult StartAuthSession(byte[] authTicketData, ulong clientSteamID)
{
if (!isInitialized || !Steamworks.SteamServer.IsValid) return Steamworks.BeginAuthResult.ServerNotConnectedToSteam;
DebugConsole.Log("SteamManager authenticating Steam client " + clientSteamID);
Steamworks.BeginAuthResult startResult = Steamworks.SteamServer.BeginAuthSession(authTicketData, clientSteamID);
if (startResult != Steamworks.BeginAuthResult.OK)
{
DebugConsole.Log("Authentication failed: failed to start auth session (" + startResult.ToString() + ")");
}
return startResult;
}
public static void StopAuthSession(ulong clientSteamID)
{
if (!isInitialized || !Steamworks.SteamServer.IsValid) return;
DebugConsole.Log("SteamManager ending auth session with Steam client " + clientSteamID);
Steamworks.SteamServer.EndSession(clientSteamID);
}
public static bool CloseServer()
{
if (!isInitialized || !Steamworks.SteamServer.IsValid) return false;
Steamworks.SteamServer.Shutdown();
return true;
}
#endregion
}
}
@@ -0,0 +1,50 @@
using Barotrauma.Networking;
using Microsoft.Xna.Framework;
using System;
namespace Barotrauma
{
partial class PhysicsBody
{
public void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
{
float MaxVel = NetConfig.MaxPhysicsBodyVelocity;
float MaxAngularVel = NetConfig.MaxPhysicsBodyAngularVelocity;
msg.Write(SimPosition.X);
msg.Write(SimPosition.Y);
#if DEBUG
if (Math.Abs(FarseerBody.LinearVelocity.X) > MaxVel ||
Math.Abs(FarseerBody.LinearVelocity.Y) > MaxVel)
{
DebugConsole.ThrowError("Item velocity out of range (" + FarseerBody.LinearVelocity + ")");
}
#endif
msg.Write(FarseerBody.Awake);
msg.Write(FarseerBody.FixedRotation);
if (!FarseerBody.FixedRotation)
{
msg.WriteRangedSingle(MathUtils.WrapAngleTwoPi(FarseerBody.Rotation), 0.0f, MathHelper.TwoPi, 8);
}
if (FarseerBody.Awake)
{
FarseerBody.Enabled = true;
FarseerBody.LinearVelocity = new Vector2(
MathHelper.Clamp(FarseerBody.LinearVelocity.X, -MaxVel, MaxVel),
MathHelper.Clamp(FarseerBody.LinearVelocity.Y, -MaxVel, MaxVel));
msg.WriteRangedSingle(FarseerBody.LinearVelocity.X, -MaxVel, MaxVel, 12);
msg.WriteRangedSingle(FarseerBody.LinearVelocity.Y, -MaxVel, MaxVel, 12);
if (!FarseerBody.FixedRotation)
{
FarseerBody.AngularVelocity = MathHelper.Clamp(FarseerBody.AngularVelocity, -MaxAngularVel, MaxAngularVel);
msg.WriteRangedSingle(FarseerBody.AngularVelocity, -MaxAngularVel, MaxAngularVel, 8);
}
}
msg.WritePadBits();
}
}
}
@@ -25,37 +25,24 @@ namespace Barotrauma
{
GameMain game = null;
#if !DEBUG || TRUE
#if !DEBUG
try
{
#endif
Console.WriteLine("Barotrauma Dedicated Server " + GameMain.Version +
" (" + AssemblyInfo.GetBuildString() + ", branch " + AssemblyInfo.GetGitBranch() + ", revision " + AssemblyInfo.GetGitRevision() + ")");
game = new GameMain(args);
DebugConsole.InputThread = null;
#if !DEBUG
if (!args.Contains("-ownerkey") && !args.Contains("-steamid"))
{
#endif
DebugConsole.InputThread = new Thread(new ThreadStart(DebugConsole.UpdateCommandLine));
DebugConsole.InputThread.IsBackground = true;
DebugConsole.InputThread.Start();
#if !DEBUG
}
else
{
Console.WriteLine("Server launched through client, command line IO disabled");
}
#endif
game.Run();
DebugConsole.InputThread?.Abort(); DebugConsole.InputThread?.Join();
if (GameSettings.SendUserStatistics) GameAnalytics.OnQuit();
if (GameSettings.SendUserStatistics) { GameAnalytics.OnQuit(); }
SteamManager.ShutDown();
#if !DEBUG || TRUE
#if !DEBUG
}
catch (Exception e)
{
CrashDump(game, "servercrashreport.log", e);
GameMain.Server?.NotifyCrash();
DebugConsole.InputThread?.Abort(); DebugConsole.InputThread?.Join();
}
#endif
}
@@ -94,11 +81,8 @@ namespace Barotrauma
sb.AppendLine("\n");
sb.AppendLine("Barotrauma seems to have crashed. Sorry for the inconvenience! ");
sb.AppendLine("\n");
#if DEBUG
sb.AppendLine("Game version " + GameMain.Version + " (debug build)");
#else
sb.AppendLine("Game version " + GameMain.Version);
#endif
sb.AppendLine("Game version " + GameMain.Version +
" (" + AssemblyInfo.GetBuildString() + ", branch " + AssemblyInfo.GetGitBranch() + ", revision " + AssemblyInfo.GetGitRevision() + ")");
sb.AppendLine("Selected content packages: " + (!GameMain.SelectedPackages.Any() ? "None" : string.Join(", ", GameMain.SelectedPackages.Select(c => c.Name))));
sb.AppendLine("Level seed: " + ((Level.Loaded == null) ? "no level loaded" : Level.Loaded.Seed));
sb.AppendLine("Loaded submarine: " + ((Submarine.MainSub == null) ? "None" : Submarine.MainSub.Name + " (" + Submarine.MainSub.MD5Hash + ")"));
@@ -113,7 +97,7 @@ namespace Barotrauma
sb.AppendLine("System info:");
sb.AppendLine(" Operating system: " + System.Environment.OSVersion + (System.Environment.Is64BitOperatingSystem ? " 64 bit" : " x86"));
sb.AppendLine("\n");
sb.AppendLine("Exception: "+exception.Message);
sb.AppendLine("Exception: " + exception.Message + " (" + exception.GetType().ToString() + ")");
sb.AppendLine("Target site: " +exception.TargetSite.ToString());
sb.AppendLine("Stack trace: ");
sb.AppendLine(exception.StackTrace);
@@ -131,6 +115,7 @@ namespace Barotrauma
}
sb.AppendLine("Last debug messages:");
DebugConsole.Clear();
for (int i = DebugConsole.Messages.Count - 1; i > 0 && i > DebugConsole.Messages.Count - 15; i-- )
{
sb.AppendLine(" "+DebugConsole.Messages[i].Time+" - "+DebugConsole.Messages[i].Text);
@@ -67,7 +67,7 @@ namespace Barotrauma
{
continue;
}
if (character.SpeciesName.ToLowerInvariant() == entities[activeEntityIndex] && Vector2.Distance(activeEntitySavedPosition, character.WorldPosition) < graceDistance)
if (character.SpeciesName.Equals(entities[activeEntityIndex], StringComparison.OrdinalIgnoreCase) && Vector2.Distance(activeEntitySavedPosition, character.WorldPosition) < graceDistance)
{
activeEntity = character;
transformationTime = 0.0;
@@ -117,7 +117,7 @@ namespace Barotrauma
{
continue;
}
if (character.SpeciesName.ToLowerInvariant() == entities[activeEntityIndex].ToLowerInvariant())
if (character.SpeciesName.Equals(entities[activeEntityIndex], StringComparison.OrdinalIgnoreCase))
{
activeEntity = character;
break;
@@ -131,7 +131,7 @@ namespace Barotrauma
{
continue;
}
if (item.prefab.Identifier.ToLowerInvariant() == entities[0].ToLowerInvariant())
if (item.prefab.Identifier.Equals(entities[0], StringComparison.OrdinalIgnoreCase))
{
activeEntity = item;
break;
@@ -70,7 +70,7 @@ namespace Barotrauma
protected ItemPrefab FindItemPrefab(string identifier)
{
return (ItemPrefab)MapEntityPrefab.List.Find(prefab => prefab is ItemPrefab && prefab.Identifier == identifier);
return (ItemPrefab)MapEntityPrefab.List.FirstOrDefault(prefab => prefab is ItemPrefab && prefab.Identifier == identifier);
}
protected Item FindRandomContainer(ICollection<Traitor> traitors, ItemPrefab targetPrefabCandidate, bool includeNew, bool includeExisting)
@@ -52,7 +52,7 @@ namespace Barotrauma
{
continue;
}
if (character.SpeciesName.ToLowerInvariant() == speciesId)
if (character.SpeciesName.Equals(speciesId, StringComparison.OrdinalIgnoreCase))
{
targetCharacter = character;
break;
@@ -142,6 +142,10 @@ namespace Barotrauma
var teamIds = new[] { Character.TeamType.Team1, Character.TeamType.Team2 };
foreach (var teamId in teamIds)
{
if (server.ConnectedClients.Count(c => c.Character != null && !c.Character.IsDead && c.TeamID == teamId) < 2)
{
continue;
}
var mission = TraitorMissionPrefab.RandomPrefab()?.Instantiate();
if (mission != null)
{
@@ -24,9 +24,9 @@ namespace Barotrauma
public static void Init()
{
var files = GameMain.Instance.GetFilesOfType(ContentType.TraitorMissions);
foreach (string file in files)
foreach (ContentFile file in files)
{
XDocument doc = XMLExtensions.TryLoadXml(file);
XDocument doc = XMLExtensions.TryLoadXml(file.Path);
if (doc?.Root == null) continue;
foreach (XElement element in doc.Root.Elements())
@@ -1,17 +0,0 @@
using Barotrauma.Networking;
namespace Barotrauma
{
partial class Mission
{
partial void ShowMessageProjSpecific(int index)
{
if (index >= Headers.Count && index >= Messages.Count) return;
string header = index < Headers.Count ? Headers[index] : "";
string message = index < Messages.Count ? Messages[index] : "";
GameServer.Log(TextManager.Get("MissionInfo") + ": " + header + " - " + message, ServerLog.MessageType.ServerMessage);
}
}
}
@@ -1,112 +0,0 @@
using Facepunch.Steamworks;
using System.Linq;
namespace Barotrauma.Steam
{
partial class SteamManager
{
#region Server
public static bool CreateServer(Networking.GameServer server, bool isPublic)
{
Instance.isInitialized = true;
ServerInit options = new ServerInit("Barotrauma", "Barotrauma")
{
GamePort = (ushort)server.Port,
QueryPort = (ushort)server.QueryPort
};
//options.QueryShareGamePort();
instance.server = new Server(AppID, options, isPublic);
if (!instance.server.IsValid)
{
instance.server.Dispose();
instance.server = null;
DebugConsole.ThrowError("Initializing Steam server failed.");
return false;
}
RefreshServerDetails(server);
server.ServerPeer.InitializeSteamServerCallbacks(instance.server);
Instance.server.LogOnAnonymous();
return true;
}
public static bool RefreshServerDetails(Networking.GameServer server)
{
if (instance?.server == null || !instance.isInitialized)
{
return false;
}
var contentPackages = GameMain.Config.SelectedContentPackages.Where(cp => cp.HasMultiplayerIncompatibleContent);
// These server state variables may be changed at any time. Note that there is no longer a mechanism
// to send the player count. The player count is maintained by steam and you should use the player
// creation/authentication functions to maintain your player count.
instance.server.ServerName = server.ServerName;
instance.server.MaxPlayers = server.ServerSettings.MaxPlayers;
instance.server.Passworded = server.ServerSettings.HasPassword;
instance.server.MapName = GameMain.NetLobbyScreen?.SelectedSub?.DisplayName ?? "";
Instance.server.SetKey("message", GameMain.Server.ServerSettings.ServerMessageText);
Instance.server.SetKey("version", GameMain.Version.ToString());
Instance.server.SetKey("playercount", GameMain.Server.ConnectedClients.Count.ToString());
Instance.server.SetKey("contentpackage", string.Join(",", contentPackages.Select(cp => cp.Name)));
Instance.server.SetKey("contentpackagehash", string.Join(",", contentPackages.Select(cp => cp.MD5hash.Hash)));
Instance.server.SetKey("contentpackageurl", string.Join(",", contentPackages.Select(cp => cp.SteamWorkshopUrl ?? "")));
Instance.server.SetKey("usingwhitelist", (server.ServerSettings.Whitelist != null && server.ServerSettings.Whitelist.Enabled).ToString());
Instance.server.SetKey("modeselectionmode", server.ServerSettings.ModeSelectionMode.ToString());
Instance.server.SetKey("subselectionmode", server.ServerSettings.SubSelectionMode.ToString());
Instance.server.SetKey("voicechatenabled", server.ServerSettings.VoiceChatEnabled.ToString());
Instance.server.SetKey("karmaenabled", server.ServerSettings.KarmaEnabled.ToString());
Instance.server.SetKey("friendlyfireenabled", server.ServerSettings.AllowFriendlyFire.ToString());
Instance.server.SetKey("allowspectating", server.ServerSettings.AllowSpectating.ToString());
Instance.server.SetKey("allowrespawn", server.ServerSettings.AllowRespawn.ToString());
Instance.server.SetKey("traitors", server.ServerSettings.TraitorsEnabled.ToString());
Instance.server.SetKey("gamestarted", server.GameStarted.ToString());
Instance.server.SetKey("gamemode", server.ServerSettings.GameModeIdentifier);
instance.server.DedicatedServer = true;
return true;
}
public static ServerAuth.StartAuthSessionResult StartAuthSession(byte[] authTicketData, ulong clientSteamID)
{
if (instance == null || !instance.isInitialized || instance.server == null) return ServerAuth.StartAuthSessionResult.ServerNotConnectedToSteam;
DebugConsole.Log("SteamManager authenticating Steam client " + clientSteamID);
ServerAuth.StartAuthSessionResult startResult = instance.server.Auth.StartSession(authTicketData, clientSteamID);
if (startResult != ServerAuth.StartAuthSessionResult.OK)
{
DebugConsole.Log("Authentication failed: failed to start auth session (" + startResult.ToString() + ")");
}
return startResult;
}
public static void StopAuthSession(ulong clientSteamID)
{
if (instance == null || !instance.isInitialized || instance.server == null) return;
DebugConsole.Log("SteamManager ending auth session with Steam client " + clientSteamID);
instance.server.Auth.EndSession(clientSteamID);
}
public static bool CloseServer()
{
if (instance == null || !instance.isInitialized || instance.server == null) return false;
instance.server.Dispose();
instance.server = null;
return true;
}
#endregion
}
}
@@ -1,50 +0,0 @@
using Barotrauma.Networking;
using Microsoft.Xna.Framework;
using System;
namespace Barotrauma
{
partial class PhysicsBody
{
public void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
{
float MaxVel = NetConfig.MaxPhysicsBodyVelocity;
float MaxAngularVel = NetConfig.MaxPhysicsBodyAngularVelocity;
msg.Write(SimPosition.X);
msg.Write(SimPosition.Y);
#if DEBUG
if (Math.Abs(body.LinearVelocity.X) > MaxVel ||
Math.Abs(body.LinearVelocity.Y) > MaxVel)
{
DebugConsole.ThrowError("Item velocity out of range (" + body.LinearVelocity + ")");
}
#endif
msg.Write(FarseerBody.Awake);
msg.Write(FarseerBody.FixedRotation);
if (!FarseerBody.FixedRotation)
{
msg.WriteRangedSingle(MathUtils.WrapAngleTwoPi(body.Rotation), 0.0f, MathHelper.TwoPi, 8);
}
if (FarseerBody.Awake)
{
body.Enabled = true;
body.LinearVelocity = new Vector2(
MathHelper.Clamp(body.LinearVelocity.X, -MaxVel, MaxVel),
MathHelper.Clamp(body.LinearVelocity.Y, -MaxVel, MaxVel));
msg.WriteRangedSingle(body.LinearVelocity.X, -MaxVel, MaxVel, 12);
msg.WriteRangedSingle(body.LinearVelocity.Y, -MaxVel, MaxVel, 12);
if (!FarseerBody.FixedRotation)
{
body.AngularVelocity = MathHelper.Clamp(body.AngularVelocity, -MaxAngularVel, MaxAngularVel);
msg.WriteRangedSingle(body.AngularVelocity, -MaxAngularVel, MaxAngularVel, 8);
}
}
msg.WritePadBits();
}
}
}
@@ -1,174 +0,0 @@
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
namespace Barotrauma
{
public static class PlayerInput
{
public static Keys selectKey = Keys.E;
public static Vector2 MousePosition
{
get { return Vector2.Zero; }
}
public static Vector2 LatestMousePosition
{
get { return Vector2.Zero; }
}
//public static MouseState GetMouseState
//{
// get { return mouseState; }
//}
//public static MouseState GetOldMouseState
//{
// get { return oldMouseState; }
//}
public static bool MouseInsideWindow
{
get { return false; }
}
public static Vector2 MouseSpeed
{
get
{
return Vector2.Zero;
}
}
public static KeyboardState GetKeyboardState
{
get { return new KeyboardState(); }
}
public static KeyboardState GetOldKeyboardState
{
get { return new KeyboardState(); }
}
public static int ScrollWheelSpeed
{
get { return 0; }
}
public static bool LeftButtonHeld()
{
return false;
}
public static bool LeftButtonDown()
{
return false;
}
public static bool LeftButtonReleased()
{
return false;
}
public static bool LeftButtonClicked()
{
return false;
}
public static bool RightButtonHeld()
{
return false;
}
public static bool RightButtonClicked()
{
return false;
}
public static bool MidButtonClicked()
{
return false;
}
public static bool MidButtonHeld()
{
return false;
}
public static bool Mouse4ButtonClicked()
{
return false;
}
public static bool Mouse4ButtonHeld()
{
return false;
}
public static bool Mouse5ButtonClicked()
{
return false;
}
public static bool Mouse5ButtonHeld()
{
return false;
}
public static bool MouseWheelUpClicked()
{
return false;
}
public static bool MouseWheelDownClicked()
{
return false;
}
public static bool DoubleClicked()
{
return false;
}
public static bool KeyHit(InputType inputType)
{
return false;
}
public static bool KeyDown(InputType inputType)
{
return false;
}
public static bool KeyUp(InputType inputType)
{
return false;
}
public static bool KeyHit(Keys button)
{
return false;
}
public static bool KeyDown(Keys button)
{
return false;
}
public static bool KeyUp(Keys button)
{
return false;
}
public static void Update(double deltaTime)
{
}
public static void UpdateVariable()
{
}
}
}
@@ -1,44 +0,0 @@
using System.Collections.Generic;
using System.Linq;
namespace Barotrauma
{
partial class Traitor
{
public class GoalRandom : Goal
{
private readonly List<Goal> allGoals;
private readonly List<Goal> selectedGoals = new List<Goal>();
public override IEnumerable<string> InfoTextKeys => base.InfoTextKeys.Concat(new string[] { "[targetname]" });
public override IEnumerable<string> InfoTextValues => base.InfoTextValues.Concat(new string[] { Target?.Name ?? "(unknown)" });
private bool isCompleted = false;
public override bool IsCompleted => isCompleted;
public override bool IsEnemy(Character character) => base.IsEnemy(character) || (!isCompleted && character == Target);
public override void Update(float deltaTime)
{
base.Update(deltaTime);
isCompleted = Target?.IsDead ?? false;
}
public override bool Start(Traitor traitor)
{
if (!base.Start(traitor))
{
return false;
}
Target = traitor.Mission.FindKillTarget(traitor.Character, Filter);
return Target != null && !Target.IsDead;
}
public GoalRandom(params Goal[] goals, int count)
{
this.goals = goals;
}
}
}
}

Some files were not shown because too many files have changed in this diff Show More