(a00338777) v0.9.2.1
This commit is contained in:
@@ -40,6 +40,7 @@
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Source\GameMain.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Source\GameSession\CrewManager.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Source\GameSession\GameMode.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Source\GameSession\GameModes\CampaignMode.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Source\GameSession\GameModes\MultiPlayerCampaign.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Source\GameSession\GameModes\SinglePlayerCampaign.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Source\GameSession\GameModes\Tutorials\BasicTutorial.cs" />
|
||||
@@ -165,6 +166,10 @@
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Source\Networking\NetEntityEvent\NetEntityEvent.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Source\Networking\NetStats.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Source\Networking\OrderChatMessage.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Source\Networking\Primitives\Peers\ClientPeer.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Source\Networking\Primitives\Peers\LidgrenClientPeer.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Source\Networking\Primitives\Peers\SteamP2PClientPeer.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Source\Networking\Primitives\Peers\SteamP2POwnerPeer.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Source\Networking\RespawnManager.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Source\Networking\ServerInfo.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Source\Networking\ServerLog.cs" />
|
||||
|
||||
@@ -93,6 +93,9 @@
|
||||
<Reference Include="nVLC, Version=3.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\Libraries\NuGet\nVLC.3.0.0\lib\net40\nVLC.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="NVorbis, Version=0.8.6.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\Libraries\NuGet\NVorbis.0.8.6\lib\net35\NVorbis.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="OpenTK, Version=3.0.1.0, Culture=neutral, PublicKeyToken=bad199fe84eb3df4, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\Libraries\NuGet\OpenTK.3.0.1\lib\net20\OpenTK.dll</HintPath>
|
||||
</Reference>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">ReleaseMac</Configuration>
|
||||
@@ -91,6 +91,9 @@
|
||||
<Reference Include="nVLC, Version=3.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\Libraries\NuGet\nVLC.3.0.0\lib\net40\nVLC.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="NVorbis, Version=0.8.6.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\Libraries\NuGet\NVorbis.0.8.6\lib\net35\NVorbis.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="OpenTK, Version=3.0.1.0, Culture=neutral, PublicKeyToken=bad199fe84eb3df4, processorArchitecture=MSIL">
|
||||
<HintPath>..\..\Libraries\NuGet\OpenTK.3.0.1\lib\net20\OpenTK.dll</HintPath>
|
||||
</Reference>
|
||||
@@ -316,8 +319,8 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup />
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Icon.bmp">
|
||||
<LogicalName>Icon.bmp</LogicalName>
|
||||
<EmbeddedResource Include="Icon.bmp">
|
||||
<LogicalName>Icon.bmp</LogicalName>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
<Import Project="ClientCode.projitems" Label="Shared" />
|
||||
|
||||
@@ -31,5 +31,5 @@ using System.Runtime.InteropServices;
|
||||
// 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.200.0")]
|
||||
[assembly: AssemblyFileVersion("0.9.1.0")]
|
||||
[assembly: AssemblyVersion("0.9.2.1")]
|
||||
[assembly: AssemblyFileVersion("0.9.2.1")]
|
||||
|
||||
@@ -185,9 +185,9 @@ namespace Barotrauma
|
||||
position += amount;
|
||||
}
|
||||
|
||||
public void ClientWrite(NetOutgoingMessage msg)
|
||||
public void ClientWrite(IWriteMessage msg)
|
||||
{
|
||||
if (Character.Controlled != null && !Character.Controlled.IsDead) return;
|
||||
if (Character.Controlled != null && !Character.Controlled.IsDead) { return; }
|
||||
|
||||
msg.Write((byte)ClientNetObject.SPECTATING_POS);
|
||||
msg.Write(position.X);
|
||||
|
||||
@@ -138,7 +138,7 @@ namespace Barotrauma
|
||||
brokenItemsCheckTimer = 1.0f;
|
||||
foreach (Item item in Item.ItemList)
|
||||
{
|
||||
if (!item.Repairables.Any(r => item.Condition < r.ShowRepairUIThreshold)) { continue; }
|
||||
if (!item.Repairables.Any(r => item.ConditionPercentage < r.ShowRepairUIThreshold)) { continue; }
|
||||
if (Submarine.VisibleEntities != null && !Submarine.VisibleEntities.Contains(item)) { continue; }
|
||||
|
||||
Vector2 diff = item.WorldPosition - character.WorldPosition;
|
||||
@@ -210,7 +210,7 @@ namespace Barotrauma
|
||||
|
||||
GUI.DrawString(spriteBatch, textPos, focusName, nameColor, Color.Black * 0.7f, 2);
|
||||
textPos.Y += offset.Y;
|
||||
if (character.FocusedCharacter.CanInventoryBeAccessed)
|
||||
if (character.FocusedCharacter.CanBeDragged)
|
||||
{
|
||||
GUI.DrawString(spriteBatch, textPos, GetCachedHudText("GrabHint", GameMain.Config.KeyBind(InputType.Grab).ToString()),
|
||||
Color.LightGreen, Color.Black, 2, GUI.SmallFont);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
using Barotrauma.Extensions;
|
||||
using Lidgren.Network;
|
||||
using Barotrauma.Networking;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
@@ -53,7 +53,7 @@ namespace Barotrauma
|
||||
if (personalityTrait != null && TextManager.Language == "English")
|
||||
{
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), headerTextArea.RectTransform),
|
||||
TextManager.AddPunctuation(':', TextManager.Get("PersonalityTrait"), personalityTrait.Name), font: font);
|
||||
TextManager.AddPunctuation(':', TextManager.Get("PersonalityTrait"), TextManager.Get("personalitytrait." + personalityTrait.Name.Replace(" ", ""))), font: font);
|
||||
}
|
||||
|
||||
//spacing
|
||||
@@ -220,7 +220,7 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
|
||||
public static CharacterInfo ClientRead(string configPath, NetBuffer inc)
|
||||
public static CharacterInfo ClientRead(string configPath, IReadMessage inc)
|
||||
{
|
||||
ushort infoID = inc.ReadUInt16();
|
||||
string newName = inc.ReadString();
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Barotrauma.Networking;
|
||||
using Lidgren.Network;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Linq;
|
||||
@@ -22,12 +21,12 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
//freeze AI characters if more than 1 seconds have passed since last update from the server
|
||||
if (lastRecvPositionUpdateTime < NetTime.Now - 1.0f)
|
||||
if (lastRecvPositionUpdateTime < Lidgren.Network.NetTime.Now - 1.0f)
|
||||
{
|
||||
AnimController.Frozen = true;
|
||||
memState.Clear();
|
||||
//hide after 2 seconds
|
||||
if (lastRecvPositionUpdateTime < NetTime.Now - 2.0f)
|
||||
if (lastRecvPositionUpdateTime < Lidgren.Network.NetTime.Now - 2.0f)
|
||||
{
|
||||
Enabled = false;
|
||||
return;
|
||||
@@ -99,22 +98,22 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void ClientWrite(NetBuffer msg, object[] extraData = null)
|
||||
public virtual void ClientWrite(IWriteMessage msg, object[] extraData = null)
|
||||
{
|
||||
if (extraData != null)
|
||||
{
|
||||
switch ((NetEntityEvent.Type)extraData[0])
|
||||
{
|
||||
case NetEntityEvent.Type.InventoryState:
|
||||
msg.WriteRangedInteger(0, 3, 0);
|
||||
msg.WriteRangedIntegerDeprecated(0, 3, 0);
|
||||
Inventory.ClientWrite(msg, extraData);
|
||||
break;
|
||||
case NetEntityEvent.Type.Treatment:
|
||||
msg.WriteRangedInteger(0, 3, 1);
|
||||
msg.WriteRangedIntegerDeprecated(0, 3, 1);
|
||||
msg.Write(AnimController.Anim == AnimController.Animation.CPR);
|
||||
break;
|
||||
case NetEntityEvent.Type.Status:
|
||||
msg.WriteRangedInteger(0, 3, 2);
|
||||
msg.WriteRangedIntegerDeprecated(0, 3, 2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -132,7 +131,7 @@ namespace Barotrauma
|
||||
msg.Write(inputCount);
|
||||
for (int i = 0; i < inputCount; i++)
|
||||
{
|
||||
msg.WriteRangedInteger(0, (int)InputNetFlags.MaxVal, (int)memInput[i].states);
|
||||
msg.WriteRangedIntegerDeprecated(0, (int)InputNetFlags.MaxVal, (int)memInput[i].states);
|
||||
msg.Write(memInput[i].intAim);
|
||||
if (memInput[i].states.HasFlag(InputNetFlags.Select) ||
|
||||
memInput[i].states.HasFlag(InputNetFlags.Deselect) ||
|
||||
@@ -147,14 +146,14 @@ namespace Barotrauma
|
||||
msg.WritePadBits();
|
||||
}
|
||||
|
||||
public virtual void ClientRead(ServerNetObject type, NetBuffer msg, float sendingTime)
|
||||
public virtual void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case ServerNetObject.ENTITY_POSITION:
|
||||
bool facingRight = AnimController.Dir > 0.0f;
|
||||
|
||||
lastRecvPositionUpdateTime = (float)NetTime.Now;
|
||||
lastRecvPositionUpdateTime = (float)Lidgren.Network.NetTime.Now;
|
||||
|
||||
AnimController.Frozen = false;
|
||||
Enabled = true;
|
||||
@@ -222,8 +221,8 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
Vector2 pos = new Vector2(
|
||||
msg.ReadFloat(),
|
||||
msg.ReadFloat());
|
||||
msg.ReadSingle(),
|
||||
msg.ReadSingle());
|
||||
float MaxVel = NetConfig.MaxPhysicsBodyVelocity;
|
||||
Vector2 linearVelocity = new Vector2(
|
||||
msg.ReadRangedSingle(-MaxVel, MaxVel, 12),
|
||||
@@ -235,7 +234,7 @@ namespace Barotrauma
|
||||
float? angularVelocity = null;
|
||||
if (!fixedRotation)
|
||||
{
|
||||
rotation = msg.ReadFloat();
|
||||
rotation = msg.ReadSingle();
|
||||
float MaxAngularVel = NetConfig.MaxPhysicsBodyAngularVelocity;
|
||||
angularVelocity = msg.ReadRangedSingle(-MaxAngularVel, MaxAngularVel, 8);
|
||||
angularVelocity = NetConfig.Quantize(angularVelocity.Value, -MaxAngularVel, MaxAngularVel, 8);
|
||||
@@ -336,7 +335,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public static Character ReadSpawnData(NetBuffer inc, bool spawn = true)
|
||||
public static Character ReadSpawnData(IReadMessage inc, bool spawn = true)
|
||||
{
|
||||
DebugConsole.NewMessage("READING CHARACTER SPAWN DATA", Color.Cyan);
|
||||
|
||||
@@ -347,7 +346,7 @@ namespace Barotrauma
|
||||
string speciesName = inc.ReadString();
|
||||
string seed = inc.ReadString();
|
||||
|
||||
Vector2 position = new Vector2(inc.ReadFloat(), inc.ReadFloat());
|
||||
Vector2 position = new Vector2(inc.ReadSingle(), inc.ReadSingle());
|
||||
|
||||
bool enabled = inc.ReadBoolean();
|
||||
|
||||
@@ -414,8 +413,17 @@ namespace Barotrauma
|
||||
|
||||
return character;
|
||||
}
|
||||
|
||||
private void ReadTraitorStatus(IReadMessage msg)
|
||||
{
|
||||
IsTraitor = msg.ReadBoolean();
|
||||
if (IsTraitor)
|
||||
{
|
||||
TraitorCurrentObjective = msg.ReadString();
|
||||
}
|
||||
}
|
||||
|
||||
private void ReadStatus(NetBuffer msg)
|
||||
private void ReadStatus(IReadMessage msg)
|
||||
{
|
||||
bool isDead = msg.ReadBoolean();
|
||||
if (isDead)
|
||||
@@ -450,7 +458,7 @@ namespace Barotrauma
|
||||
else
|
||||
{
|
||||
if (IsDead) Revive();
|
||||
|
||||
|
||||
CharacterHealth.ClientRead(msg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using Barotrauma.Items.Components;
|
||||
using Barotrauma.Networking;
|
||||
using Lidgren.Network;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
@@ -1375,7 +1374,7 @@ namespace Barotrauma
|
||||
(int)(limbHealth.HighlightArea.Height * scale));
|
||||
}
|
||||
|
||||
public void ClientRead(NetBuffer inc)
|
||||
public void ClientRead(IReadMessage inc)
|
||||
{
|
||||
List<Pair<AfflictionPrefab, float>> newAfflictions = new List<Pair<AfflictionPrefab, float>>();
|
||||
|
||||
|
||||
@@ -441,7 +441,7 @@ namespace Barotrauma
|
||||
float herpesStrength = character.CharacterHealth.GetAfflictionStrength("spaceherpes");
|
||||
if (herpesStrength > 0.0f)
|
||||
{
|
||||
DrawWearable(HerpesSprite, depthStep, spriteBatch, color * (herpesStrength / 100.0f), spriteEffect);
|
||||
DrawWearable(HerpesSprite, depthStep, spriteBatch, color * Math.Min(herpesStrength / 10.0f, 1.0f), spriteEffect);
|
||||
depthStep += 0.000001f;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -199,6 +199,7 @@ namespace Barotrauma
|
||||
return client.HasPermission(ClientPermissions.Kick);
|
||||
case "ban":
|
||||
case "banip":
|
||||
case "banendpoint":
|
||||
return client.HasPermission(ClientPermissions.Ban);
|
||||
case "unban":
|
||||
case "unbanip":
|
||||
@@ -317,7 +318,13 @@ namespace Barotrauma
|
||||
|
||||
private static void AssignRelayToServer(string names, bool relay)
|
||||
{
|
||||
commands.First(c => c.names.Intersect(names.Split('|')).Count() > 0).RelayToServer = relay;
|
||||
Command command = commands.Find(c => c.names.Intersect(names.Split('|')).Count() > 0);
|
||||
if (command == null)
|
||||
{
|
||||
DebugConsole.Log("Could not assign to relay to server: " + names);
|
||||
return;
|
||||
}
|
||||
command.RelayToServer = relay;
|
||||
}
|
||||
|
||||
private static void InitProjectSpecific()
|
||||
@@ -358,16 +365,23 @@ namespace Barotrauma
|
||||
}
|
||||
}));
|
||||
|
||||
commands.Add(new Command("startclient", "", (string[] args) =>
|
||||
commands.Add(new Command("startlidgrenclient", "", (string[] args) =>
|
||||
{
|
||||
if (args.Length == 0) return;
|
||||
|
||||
if (GameMain.Client == null)
|
||||
{
|
||||
GameMain.Client = new GameClient("Name", args[0]);
|
||||
GameMain.Client = new GameClient("Name", args[0], 0);
|
||||
}
|
||||
}));
|
||||
|
||||
commands.Add(new Command("startsteamp2pclient", "", (string[] args) =>
|
||||
{
|
||||
if (GameMain.Client == null)
|
||||
{
|
||||
GameMain.Client = new GameClient("Name", null, 76561198977850505); //this is juan's alt account, feel free to abuse this one
|
||||
}
|
||||
}));
|
||||
|
||||
commands.Add(new Command("enablecheats", "enablecheats: Enables cheat commands and disables Steam achievements during this play session.", (string[] args) =>
|
||||
{
|
||||
@@ -465,10 +479,16 @@ namespace Barotrauma
|
||||
|
||||
commands.Add(new Command("clientlist", "", (string[] args) => { }));
|
||||
AssignRelayToServer("clientlist", true);
|
||||
commands.Add(new Command("say", "", (string[] args) => { }));
|
||||
AssignRelayToServer("say", true);
|
||||
commands.Add(new Command("msg", "", (string[] args) => { }));
|
||||
AssignRelayToServer("msg", true);
|
||||
commands.Add(new Command("setmaxplayers|maxplayers", "", (string[] args) => { }));
|
||||
AssignRelayToServer("setmaxplayers", true);
|
||||
commands.Add(new Command("setpassword|password", "", (string[] args) => { }));
|
||||
AssignRelayToServer("setpassword", true);
|
||||
commands.Add(new Command("traitorlist", "", (string[] args) => { }));
|
||||
AssignRelayToServer("traitorlist", true);
|
||||
|
||||
AssignOnExecute("control", (string[] args) =>
|
||||
{
|
||||
@@ -551,6 +571,7 @@ namespace Barotrauma
|
||||
if (args.Length < 3)
|
||||
{
|
||||
ThrowError("Not enough arguments provided! At least three required.");
|
||||
return;
|
||||
}
|
||||
if (!byte.TryParse(args[0], out byte r))
|
||||
{
|
||||
@@ -952,7 +973,36 @@ namespace Barotrauma
|
||||
}
|
||||
}, isCheat: false));
|
||||
|
||||
commands.Add(new Command("setentityproperties", "setentityproperties [property name] [value]: Sets the value of some property on all selected items/structures in the sub editor.", (string[] args) =>
|
||||
{
|
||||
if (args.Length != 2 || Screen.Selected != GameMain.SubEditorScreen) { return; }
|
||||
foreach (MapEntity me in MapEntity.SelectedList)
|
||||
{
|
||||
if (me is ISerializableEntity serializableEntity)
|
||||
{
|
||||
if (serializableEntity.SerializableProperties == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (!serializableEntity.SerializableProperties.TryGetValue(args[0].ToLowerInvariant(), out SerializableProperty property))
|
||||
{
|
||||
NewMessage("Property \"" + args[0] + "\" not found in the entity \"" + me.ToString() + "\".", Color.Orange);
|
||||
continue;
|
||||
}
|
||||
if (!property.TrySetValue(me, args[1]))
|
||||
{
|
||||
NewMessage("Failed to set the value of \"" + args[0] + "\" to \"" + args[1] + "\" on the entity \"" + me.ToString() + "\".", Color.Orange);
|
||||
}
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
#if DEBUG
|
||||
commands.Add(new Command("printreceivertransfers", "", (string[] args) =>
|
||||
{
|
||||
GameMain.Client.PrintReceiverTransters();
|
||||
}));
|
||||
|
||||
commands.Add(new Command("checkmissingloca", "", (string[] args) =>
|
||||
{
|
||||
foreach (MapEntityPrefab me in MapEntityPrefab.List)
|
||||
@@ -1201,6 +1251,8 @@ namespace Barotrauma
|
||||
{
|
||||
GameMain.Config.MusicVolume = 0.5f;
|
||||
GameMain.Config.SoundVolume = 0.5f;
|
||||
GameMain.Config.DynamicRangeCompressionEnabled = true;
|
||||
GameMain.Config.VoipAttenuationEnabled = true;
|
||||
NewMessage("Music and sound volume set to 0.5", Color.Green);
|
||||
|
||||
GameMain.Config.GraphicsWidth = 0;
|
||||
@@ -1416,11 +1468,11 @@ namespace Barotrauma
|
||||
);
|
||||
|
||||
AssignOnClientExecute(
|
||||
"banip",
|
||||
"banendpoint|banip",
|
||||
(string[] args) =>
|
||||
{
|
||||
if (GameMain.Client == null || args.Length == 0) return;
|
||||
ShowQuestionPrompt("Reason for banning the ip \"" + args[0] + "\"?", (reason) =>
|
||||
ShowQuestionPrompt("Reason for banning the endpoint \"" + args[0] + "\"?", (reason) =>
|
||||
{
|
||||
ShowQuestionPrompt("Enter the duration of the ban (leave empty to ban permanently, or use the format \"[days] d [hours] h\")", (duration) =>
|
||||
{
|
||||
@@ -1436,7 +1488,7 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
GameMain.Client.SendConsoleCommand(
|
||||
"banip " +
|
||||
"banendpoint " +
|
||||
args[0] + " " +
|
||||
(banDuration.HasValue ? banDuration.Value.TotalSeconds.ToString() : "0") + " " +
|
||||
reason);
|
||||
@@ -1779,6 +1831,21 @@ namespace Barotrauma
|
||||
character.ReloadHead(id, hairIndex, beardIndex, moustacheIndex, faceAttachmentIndex);
|
||||
}
|
||||
}, isCheat: true));
|
||||
|
||||
commands.Add(new Command("spawnsub", "spawnsub [subname]: Spawn a submarine at the position of the cursor", (string[] args) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
Submarine spawnedSub = Submarine.Load(args[0], false);
|
||||
spawnedSub.SetPosition(GameMain.GameScreen.Cam.ScreenToWorld(PlayerInput.MousePosition));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
string errorMsg = "Failed to spawn a submarine. Arguments: \"" + string.Join(" ", args) + "\".";
|
||||
ThrowError(errorMsg, e);
|
||||
GameAnalyticsManager.AddErrorEventOnce("DebugConsole.SpawnSubmarine:Error", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg + '\n' + e.Message + '\n' + e.StackTrace);
|
||||
}
|
||||
}, isCheat: true));
|
||||
}
|
||||
|
||||
private static void ReloadWearables(Character character, int variant = 0)
|
||||
|
||||
@@ -4,16 +4,13 @@ namespace Barotrauma
|
||||
{
|
||||
partial class Mission
|
||||
{
|
||||
public void ShowMessage(int index)
|
||||
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] : "";
|
||||
|
||||
//TODO: reimplement
|
||||
//GameServer.Log(TextManager.Get("MissionInfo") + ": " + header + " - " + message, ServerLog.MessageType.ServerMessage);
|
||||
|
||||
new GUIMessageBox(header, message);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,19 +5,14 @@ namespace Barotrauma
|
||||
{
|
||||
partial class MissionMode : GameMode
|
||||
{
|
||||
public override void MsgBox()
|
||||
public override void ShowStartMessage()
|
||||
{
|
||||
if (mission == null) return;
|
||||
|
||||
var missionMsg = new GUIMessageBox(mission.Name, mission.Description, new Vector2(0.25f, 0.0f), new Point(400, 200))
|
||||
new GUIMessageBox(mission.Name, mission.Description, new Vector2(0.25f, 0.0f), new Point(400, 200))
|
||||
{
|
||||
UserData = "missionstartmessage"
|
||||
};
|
||||
|
||||
#if SERVER
|
||||
Networking.GameServer.Log(TextManager.Get("Mission") + ": " + mission.Name, Networking.ServerLog.MessageType.ServerMessage);
|
||||
Networking.GameServer.Log(mission.Description, Networking.ServerLog.MessageType.ServerMessage);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -310,6 +310,16 @@ namespace Barotrauma
|
||||
"Sounds (Ctrl+S to hide): ", Color.White, Color.Black * 0.5f, 0, SmallFont);
|
||||
y += 15;
|
||||
|
||||
DrawString(spriteBatch, new Vector2(500, y),
|
||||
"Current playback amplitude: " + GameMain.SoundManager.PlaybackAmplitude.ToString(), Color.White, Color.Black * 0.5f, 0, SmallFont);
|
||||
|
||||
y += 15;
|
||||
|
||||
DrawString(spriteBatch, new Vector2(500, y),
|
||||
"Compressed dynamic range gain: " + GameMain.SoundManager.CompressionDynamicRangeGain.ToString(), Color.White, Color.Black * 0.5f, 0, SmallFont);
|
||||
|
||||
y += 15;
|
||||
|
||||
DrawString(spriteBatch, new Vector2(500, y),
|
||||
"Loaded sounds: " + GameMain.SoundManager.LoadedSoundCount + " (" + GameMain.SoundManager.UniqueLoadedSoundCount + " unique)", Color.White, Color.Black * 0.5f, 0, SmallFont);
|
||||
y += 15;
|
||||
@@ -343,18 +353,21 @@ namespace Barotrauma
|
||||
soundStr += " (looping)";
|
||||
clr = Color.Yellow;
|
||||
}
|
||||
|
||||
if (playingSoundChannel.IsStream)
|
||||
{
|
||||
soundStr += " (streaming)";
|
||||
clr = Color.Lime;
|
||||
}
|
||||
|
||||
if (!playingSoundChannel.IsPlaying)
|
||||
{
|
||||
soundStr += " (stopped)";
|
||||
clr *= 0.5f;
|
||||
}
|
||||
else if (playingSoundChannel.Muffled)
|
||||
{
|
||||
soundStr += " (muffled)";
|
||||
clr = Color.Lerp(clr, Color.LightGray, 0.5f);
|
||||
}
|
||||
}
|
||||
|
||||
DrawString(spriteBatch, new Vector2(500, y), soundStr, clr, Color.Black * 0.5f, 0, SmallFont);
|
||||
@@ -640,6 +653,12 @@ namespace Barotrauma
|
||||
return MouseOn;
|
||||
}
|
||||
|
||||
public static bool HasSizeChanged(Point referenceResolution, float referenceUIScale, float referenceHUDScale)
|
||||
{
|
||||
return GameMain.GraphicsWidth != referenceResolution.X || GameMain.GraphicsHeight != referenceResolution.Y ||
|
||||
referenceUIScale != Inventory.UIScale || referenceHUDScale != Scale;
|
||||
}
|
||||
|
||||
public static void Update(float deltaTime)
|
||||
{
|
||||
HandlePersistingElements(deltaTime);
|
||||
@@ -1461,6 +1480,9 @@ namespace Barotrauma
|
||||
|
||||
if (pauseMenuOpen)
|
||||
{
|
||||
Inventory.draggingItem = null;
|
||||
Inventory.DraggingInventory = null;
|
||||
|
||||
PauseMenu = new GUIFrame(new RectTransform(Vector2.One, Canvas), style: null, color: Color.Black * 0.5f);
|
||||
|
||||
var pauseMenuInner = new GUIFrame(new RectTransform(new Vector2(0.13f, 0.35f), PauseMenu.RectTransform, Anchor.Center) { MinSize = new Point(200, 300) });
|
||||
|
||||
@@ -67,6 +67,21 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
// TODO: refactor?
|
||||
|
||||
public GUIComponent FindChild(Func<GUIComponent, bool> predicate, bool recursive = false)
|
||||
{
|
||||
var matchingChild = Children.FirstOrDefault(predicate);
|
||||
if (recursive && matchingChild == null)
|
||||
{
|
||||
foreach (GUIComponent child in Children)
|
||||
{
|
||||
matchingChild = child.FindChild(predicate, recursive);
|
||||
if (matchingChild != null) return matchingChild;
|
||||
}
|
||||
}
|
||||
|
||||
return matchingChild;
|
||||
}
|
||||
public GUIComponent FindChild(object userData, bool recursive = false)
|
||||
{
|
||||
var matchingChild = Children.FirstOrDefault(c => c.userData == userData);
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using EventInput;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using Microsoft.Xna.Framework.Input;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
public class GUIDropDown : GUIComponent
|
||||
public class GUIDropDown : GUIComponent, IKeyboardSubscriber
|
||||
{
|
||||
public delegate bool OnSelectedHandler(GUIComponent selected, object obj = null);
|
||||
public OnSelectedHandler OnSelected;
|
||||
@@ -42,10 +44,22 @@ namespace Barotrauma
|
||||
set { button.Enabled = value; }
|
||||
}
|
||||
|
||||
public GUIComponent Selected
|
||||
public GUIComponent SelectedComponent
|
||||
{
|
||||
get { return listBox.SelectedComponent; }
|
||||
}
|
||||
|
||||
public bool Selected
|
||||
{
|
||||
get
|
||||
{
|
||||
return Dropped;
|
||||
}
|
||||
set
|
||||
{
|
||||
Dropped = value;
|
||||
}
|
||||
}
|
||||
|
||||
public GUIListBox ListBox
|
||||
{
|
||||
@@ -69,6 +83,30 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public void ReceiveTextInput(char inputChar)
|
||||
{
|
||||
GUI.KeyboardDispatcher.Subscriber = null;
|
||||
}
|
||||
public void ReceiveTextInput(string text) { }
|
||||
public void ReceiveCommandInput(char command) { }
|
||||
|
||||
public void ReceiveSpecialInput(Keys key)
|
||||
{
|
||||
switch (key)
|
||||
{
|
||||
case Keys.Up:
|
||||
case Keys.Down:
|
||||
listBox.ReceiveSpecialInput(key);
|
||||
GUI.KeyboardDispatcher.Subscriber = this;
|
||||
break;
|
||||
case Keys.Enter:
|
||||
case Keys.Space:
|
||||
case Keys.Escape:
|
||||
GUI.KeyboardDispatcher.Subscriber = null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private List<object> selectedDataMultiple = new List<object>();
|
||||
public IEnumerable<object> SelectedDataMultiple
|
||||
{
|
||||
@@ -287,6 +325,12 @@ namespace Barotrauma
|
||||
{
|
||||
OnDropped?.Invoke(this, userData);
|
||||
listBox.UpdateScrollBarSize();
|
||||
|
||||
GUI.KeyboardDispatcher.Subscriber = this;
|
||||
}
|
||||
else if (GUI.KeyboardDispatcher.Subscriber == this)
|
||||
{
|
||||
GUI.KeyboardDispatcher.Subscriber = null;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -343,6 +387,10 @@ namespace Barotrauma
|
||||
if (!listBoxRect.Contains(PlayerInput.MousePosition) && !button.Rect.Contains(PlayerInput.MousePosition))
|
||||
{
|
||||
Dropped = false;
|
||||
if (GUI.KeyboardDispatcher.Subscriber == this)
|
||||
{
|
||||
GUI.KeyboardDispatcher.Subscriber = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -651,7 +651,9 @@ namespace Barotrauma
|
||||
case Keys.Up:
|
||||
SelectPrevious();
|
||||
break;
|
||||
default:
|
||||
case Keys.Enter:
|
||||
case Keys.Space:
|
||||
case Keys.Escape:
|
||||
GUI.KeyboardDispatcher.Subscriber = null;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ namespace Barotrauma
|
||||
public TextGetterHandler TextGetter;
|
||||
|
||||
public bool Wrap;
|
||||
private bool playerInput;
|
||||
|
||||
public bool RoundToNearestPixel = true;
|
||||
|
||||
@@ -193,7 +194,7 @@ namespace Barotrauma
|
||||
/// If the rectT height is set 0, the height is calculated from the text.
|
||||
/// </summary>
|
||||
public GUITextBlock(RectTransform rectT, string text, Color? textColor = null, ScalableFont font = null,
|
||||
Alignment textAlignment = Alignment.Left, bool wrap = false, string style = "", Color? color = null)
|
||||
Alignment textAlignment = Alignment.Left, bool wrap = false, string style = "", Color? color = null, bool playerInput = false)
|
||||
: base(style, rectT)
|
||||
{
|
||||
if (color.HasValue)
|
||||
@@ -208,6 +209,7 @@ namespace Barotrauma
|
||||
this.textAlignment = textAlignment;
|
||||
this.Wrap = wrap;
|
||||
this.Text = text ?? "";
|
||||
this.playerInput = playerInput;
|
||||
if (rectT.Rect.Height == 0 && !string.IsNullOrEmpty(text))
|
||||
{
|
||||
CalculateHeightFromText();
|
||||
@@ -254,7 +256,7 @@ namespace Barotrauma
|
||||
|
||||
if (Wrap && rect.Width > 0)
|
||||
{
|
||||
wrappedText = ToolBox.WrapText(text, rect.Width - padding.X - padding.Z, Font, textScale);
|
||||
wrappedText = ToolBox.WrapText(text, rect.Width - padding.X - padding.Z, Font, textScale, playerInput);
|
||||
TextSize = MeasureText(wrappedText);
|
||||
}
|
||||
else if (OverflowClip)
|
||||
|
||||
@@ -199,6 +199,12 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public Vector4 Padding
|
||||
{
|
||||
get { return textBlock.Padding; }
|
||||
set { textBlock.Padding = value; }
|
||||
}
|
||||
|
||||
// TODO: should this be defined in the stylesheet?
|
||||
public Color SelectionColor { get; set; } = Color.White * 0.25f;
|
||||
|
||||
@@ -229,7 +235,7 @@ namespace Barotrauma
|
||||
this.color = color ?? Color.White;
|
||||
frame = new GUIFrame(new RectTransform(Vector2.One, rectT, Anchor.Center), style, color);
|
||||
GUI.Style.Apply(frame, style == "" ? "GUITextBox" : style);
|
||||
textBlock = new GUITextBlock(new RectTransform(Vector2.One, frame.RectTransform, Anchor.Center), text, textColor, font, textAlignment, wrap);
|
||||
textBlock = new GUITextBlock(new RectTransform(Vector2.One, frame.RectTransform, Anchor.Center), text, textColor, font, textAlignment, wrap, playerInput: true);
|
||||
GUI.Style.Apply(textBlock, "", this);
|
||||
CaretEnabled = true;
|
||||
caretPosDirty = true;
|
||||
@@ -308,6 +314,7 @@ namespace Barotrauma
|
||||
|
||||
protected List<Tuple<Vector2, int>> GetAllPositions()
|
||||
{
|
||||
float halfHeight = Font.MeasureString("T").Y * 0.5f;
|
||||
string textDrawn = Censor ? textBlock.CensoredText : textBlock.WrappedText;
|
||||
var positions = new List<Tuple<Vector2, int>>();
|
||||
if (textDrawn.Contains("\n"))
|
||||
@@ -323,9 +330,9 @@ namespace Barotrauma
|
||||
for (int j = 0; j <= line.Length; j++)
|
||||
{
|
||||
Vector2 lineTextSize = Font.MeasureString(line.Substring(0, j));
|
||||
Vector2 indexPos = new Vector2(lineTextSize.X + textBlock.Padding.X, totalTextHeight + textBlock.Padding.Y);
|
||||
Vector2 indexPos = new Vector2(lineTextSize.X + textBlock.Padding.X, totalTextHeight + textBlock.Padding.Y - halfHeight);
|
||||
//DebugConsole.NewMessage($"index: {index}, pos: {indexPos}", Color.AliceBlue);
|
||||
positions.Add(new Tuple<Vector2, int>(textBlock.Rect.Location.ToVector2() + indexPos, index + j));
|
||||
positions.Add(new Tuple<Vector2, int>(indexPos, index + j));
|
||||
}
|
||||
index = totalIndex;
|
||||
}
|
||||
@@ -336,9 +343,9 @@ namespace Barotrauma
|
||||
for (int i = 0; i <= textBlock.Text.Length; i++)
|
||||
{
|
||||
Vector2 textSize = Font.MeasureString(textDrawn.Substring(0, i));
|
||||
Vector2 indexPos = new Vector2(textSize.X + textBlock.Padding.X, textSize.Y + textBlock.Padding.Y) + textBlock.TextPos - textBlock.Origin;
|
||||
Vector2 indexPos = new Vector2(textSize.X + textBlock.Padding.X, textSize.Y + textBlock.Padding.Y - halfHeight) + textBlock.TextPos - textBlock.Origin;
|
||||
//DebugConsole.NewMessage($"index: {i}, pos: {indexPos}", Color.WhiteSmoke);
|
||||
positions.Add(new Tuple<Vector2, int>(textBlock.Rect.Location.ToVector2() + indexPos, i));
|
||||
positions.Add(new Tuple<Vector2, int>(indexPos, i));
|
||||
}
|
||||
}
|
||||
return positions;
|
||||
@@ -346,10 +353,64 @@ namespace Barotrauma
|
||||
|
||||
public int GetCaretIndexFromScreenPos(Vector2 pos)
|
||||
{
|
||||
var positions = GetAllPositions().OrderBy(p => Vector2.DistanceSquared(p.Item1, pos));
|
||||
var posIndex = positions.FirstOrDefault();
|
||||
return GetCaretIndexFromLocalPos(pos - textBlock.Rect.Location.ToVector2());
|
||||
}
|
||||
|
||||
public int GetCaretIndexFromLocalPos(Vector2 pos)
|
||||
{
|
||||
var positions = GetAllPositions();
|
||||
if (positions.Count==0) { return 0; }
|
||||
float halfHeight = Font.MeasureString("T").Y * 0.5f;
|
||||
|
||||
var currPosition = positions[0];
|
||||
|
||||
for (int i=1;i<positions.Count;i++)
|
||||
{
|
||||
var p1 = positions[i];
|
||||
var p2 = currPosition;
|
||||
|
||||
float diffY = Math.Abs(p1.Item1.Y - pos.Y) - Math.Abs(p2.Item1.Y - pos.Y);
|
||||
if (diffY < -3.0f)
|
||||
{
|
||||
currPosition = p1; continue;
|
||||
}
|
||||
else if (diffY > 3.0f)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
diffY = Math.Abs(p1.Item1.Y - pos.Y);
|
||||
if (diffY < halfHeight)
|
||||
{
|
||||
//we are on this line, select the nearest character
|
||||
float diffX = Math.Abs(p1.Item1.X - pos.X) - Math.Abs(p2.Item1.X - pos.X);
|
||||
if (diffX < -1.0f)
|
||||
{
|
||||
currPosition = p1; continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//we are on a different line, preserve order
|
||||
if (p1.Item2 < p2.Item2)
|
||||
{
|
||||
if (p1.Item1.Y > pos.Y) { currPosition = p1; }
|
||||
}
|
||||
else if (p1.Item2 > p2.Item2)
|
||||
{
|
||||
if (p1.Item1.Y < pos.Y) { currPosition = p1; }
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
//GUI.AddMessage($"index: {posIndex.Item2}, pos: {posIndex.Item1}", Color.WhiteSmoke);
|
||||
return posIndex != null ? posIndex.Item2 : textBlock.Text.Length;
|
||||
return currPosition != null ? currPosition.Item2 : textBlock.Text.Length;
|
||||
}
|
||||
|
||||
public void Select()
|
||||
@@ -674,9 +735,9 @@ namespace Barotrauma
|
||||
{
|
||||
InitSelectionStart();
|
||||
}
|
||||
float lineHeight = Font.MeasureString(Text).Y;
|
||||
int newIndex = GetCaretIndexFromScreenPos(new Vector2(CaretScreenPos.X, CaretScreenPos.Y - lineHeight / 2));
|
||||
CaretIndex = newIndex != CaretIndex ? newIndex : 0;
|
||||
float lineHeight = Font.MeasureString("T").Y;
|
||||
int newIndex = GetCaretIndexFromLocalPos(new Vector2(caretPos.X, caretPos.Y-lineHeight));
|
||||
CaretIndex = newIndex;
|
||||
caretTimer = 0;
|
||||
HandleSelection();
|
||||
break;
|
||||
@@ -685,9 +746,9 @@ namespace Barotrauma
|
||||
{
|
||||
InitSelectionStart();
|
||||
}
|
||||
lineHeight = Font.MeasureString(Text).Y;
|
||||
newIndex = GetCaretIndexFromScreenPos(new Vector2(CaretScreenPos.X, CaretScreenPos.Y + lineHeight * 2));
|
||||
CaretIndex = newIndex != CaretIndex ? newIndex : Text.Length;
|
||||
lineHeight = Font.MeasureString("T").Y;
|
||||
newIndex = GetCaretIndexFromLocalPos(new Vector2(caretPos.X, caretPos.Y+lineHeight));
|
||||
CaretIndex = newIndex;
|
||||
caretTimer = 0;
|
||||
HandleSelection();
|
||||
break;
|
||||
|
||||
@@ -114,10 +114,13 @@ namespace Barotrauma
|
||||
if (IsMouseOver || (!RequireMouseOn && selectedWidgets.Contains(this) && PlayerInput.LeftButtonHeld()))
|
||||
{
|
||||
Hovered?.Invoke();
|
||||
if ((multiselect && !selectedWidgets.Contains(this)) || selectedWidgets.None())
|
||||
if (RequireMouseOn || PlayerInput.LeftButtonDown())
|
||||
{
|
||||
selectedWidgets.Add(this);
|
||||
Selected?.Invoke();
|
||||
if ((multiselect && !selectedWidgets.Contains(this)) || selectedWidgets.None())
|
||||
{
|
||||
selectedWidgets.Add(this);
|
||||
Selected?.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (selectedWidgets.Contains(this))
|
||||
|
||||
@@ -101,6 +101,10 @@ namespace Barotrauma
|
||||
|
||||
private GameTime fixedTime;
|
||||
|
||||
public string ConnectName;
|
||||
public string ConnectEndpoint;
|
||||
public UInt64 ConnectLobby;
|
||||
|
||||
private static SpriteBatch spriteBatch;
|
||||
|
||||
private Viewport defaultViewport;
|
||||
@@ -175,6 +179,12 @@ namespace Barotrauma
|
||||
|
||||
ConsoleArguments = args;
|
||||
|
||||
ConnectName = null;
|
||||
ConnectEndpoint = null;
|
||||
ConnectLobby = 0;
|
||||
|
||||
ToolBox.ParseConnectCommand(ConsoleArguments, out ConnectName, out ConnectEndpoint, out ConnectLobby);
|
||||
|
||||
GUI.KeyboardDispatcher = new EventInput.KeyboardDispatcher(Window);
|
||||
|
||||
PerformanceCounter = new PerformanceCounter();
|
||||
@@ -355,13 +365,13 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
SoundManager = new Sounds.SoundManager();
|
||||
SoundManager.SetCategoryGainMultiplier("default", Config.SoundVolume);
|
||||
SoundManager.SetCategoryGainMultiplier("ui", Config.SoundVolume);
|
||||
SoundManager.SetCategoryGainMultiplier("waterambience", Config.SoundVolume);
|
||||
SoundManager.SetCategoryGainMultiplier("music", Config.MusicVolume);
|
||||
SoundManager.SetCategoryGainMultiplier("voip", Config.VoiceChatVolume * 20.0f);
|
||||
SoundManager.SetCategoryGainMultiplier("default", Config.SoundVolume, 0);
|
||||
SoundManager.SetCategoryGainMultiplier("ui", Config.SoundVolume, 0);
|
||||
SoundManager.SetCategoryGainMultiplier("waterambience", Config.SoundVolume, 0);
|
||||
SoundManager.SetCategoryGainMultiplier("music", Config.MusicVolume, 0);
|
||||
SoundManager.SetCategoryGainMultiplier("voip", Config.VoiceChatVolume * 20.0f, 0);
|
||||
|
||||
if (ConsoleArguments.Contains("skipintro")) {
|
||||
if (ConsoleArguments.Contains("-skipintro")) {
|
||||
Config.EnableSplashScreen = false;
|
||||
}
|
||||
|
||||
@@ -390,7 +400,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (SteamManager.AutoUpdateWorkshopItems())
|
||||
{
|
||||
ContentPackage.LoadAll(ContentPackage.Folder);
|
||||
ContentPackage.LoadAll();
|
||||
Config.ReloadContentPackages();
|
||||
}
|
||||
}
|
||||
@@ -494,7 +504,12 @@ namespace Barotrauma
|
||||
|
||||
if (SteamManager.USE_STEAM)
|
||||
{
|
||||
SteamWorkshopScreen = new SteamWorkshopScreen();
|
||||
SteamWorkshopScreen = new SteamWorkshopScreen();
|
||||
if (SteamManager.IsInitialized)
|
||||
{
|
||||
SteamManager.Instance.Friends.OnInvitedToGame += OnInvitedToGame;
|
||||
SteamManager.Instance.Lobby.OnLobbyJoinRequested += OnLobbyJoinRequested;
|
||||
}
|
||||
}
|
||||
SubEditorScreen = new SubEditorScreen();
|
||||
|
||||
@@ -594,6 +609,18 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public void OnInvitedToGame(Facepunch.Steamworks.SteamFriend friend, string connectCommand)
|
||||
{
|
||||
ToolBox.ParseConnectCommand(connectCommand.Split(' '), out ConnectName, out ConnectEndpoint, out ConnectLobby);
|
||||
|
||||
DebugConsole.NewMessage(ConnectName+", "+ConnectEndpoint,Color.Yellow);
|
||||
}
|
||||
|
||||
public void OnLobbyJoinRequested(UInt64 lobbyId)
|
||||
{
|
||||
SteamManager.JoinLobby(lobbyId, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Allows the game to run logic such as updating the world,
|
||||
/// checking for collisions, gathering input, and playing audio.
|
||||
@@ -622,7 +649,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (WindowActive || !Config.MuteOnFocusLost)
|
||||
{
|
||||
SoundManager.ListenerGain = 1.0f;
|
||||
SoundManager.ListenerGain = SoundManager.CompressionDynamicRangeGain;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -674,6 +701,40 @@ namespace Barotrauma
|
||||
}
|
||||
else if (hasLoaded)
|
||||
{
|
||||
if (ConnectLobby != 0)
|
||||
{
|
||||
if (Client != null)
|
||||
{
|
||||
Client.Disconnect();
|
||||
Client = null;
|
||||
|
||||
GameMain.MainMenuScreen.Select();
|
||||
}
|
||||
Steam.SteamManager.JoinLobby(ConnectLobby, true);
|
||||
|
||||
ConnectLobby = 0;
|
||||
ConnectEndpoint = null;
|
||||
ConnectName = null;
|
||||
}
|
||||
else if (!string.IsNullOrWhiteSpace(ConnectEndpoint))
|
||||
{
|
||||
if (Client != null)
|
||||
{
|
||||
Client.Disconnect();
|
||||
Client = null;
|
||||
|
||||
GameMain.MainMenuScreen.Select();
|
||||
}
|
||||
UInt64 serverSteamId = SteamManager.SteamIDStringToUInt64(ConnectEndpoint);
|
||||
Client = new GameClient(SteamManager.GetUsername(),
|
||||
serverSteamId != 0 ? null : ConnectEndpoint,
|
||||
serverSteamId,
|
||||
string.IsNullOrWhiteSpace(ConnectName) ? ConnectEndpoint : ConnectName);
|
||||
ConnectLobby = 0;
|
||||
ConnectEndpoint = null;
|
||||
ConnectName = null;
|
||||
}
|
||||
|
||||
SoundPlayer.Update((float)Timing.Step);
|
||||
|
||||
if (PlayerInput.KeyHit(Keys.Escape) && WindowActive)
|
||||
@@ -754,6 +815,8 @@ namespace Barotrauma
|
||||
|
||||
SteamManager.Update((float)Timing.Step);
|
||||
|
||||
SoundManager?.Update();
|
||||
|
||||
Timing.Accumulator -= Timing.Step;
|
||||
|
||||
sw.Stop();
|
||||
|
||||
@@ -1251,6 +1251,7 @@ namespace Barotrauma
|
||||
if (!hoverArea.Contains(PlayerInput.MousePosition) || PlayerInput.RightButtonClicked())
|
||||
{
|
||||
orderTargetFrame = null;
|
||||
OrderOptionButtons.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1361,7 +1362,9 @@ namespace Barotrauma
|
||||
{
|
||||
reportButtonFrame.Visible = true;
|
||||
|
||||
var reportButtonParent = ChatBox ?? GameMain.Client.ChatBox;
|
||||
var reportButtonParent = ChatBox ?? GameMain.Client?.ChatBox;
|
||||
if (reportButtonParent == null) { return; }
|
||||
|
||||
reportButtonFrame.RectTransform.AbsoluteOffset = new Point(
|
||||
Math.Min(reportButtonParent.GUIFrame.Rect.X, reportButtonParent.ToggleButton.Rect.X) - reportButtonFrame.Rect.Width - (int)(10 * GUI.Scale),
|
||||
reportButtonParent.GUIFrame.Rect.Y);
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using Barotrauma.Networking;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
abstract partial class CampaignMode : GameMode
|
||||
{
|
||||
public override void ShowStartMessage()
|
||||
{
|
||||
if (Mission == null) return;
|
||||
|
||||
new GUIMessageBox(Mission.Name, Mission.Description, new Vector2(0.25f, 0.0f), new Point(400, 200))
|
||||
{
|
||||
UserData = "missionstartmessage"
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
using Barotrauma.Networking;
|
||||
using Lidgren.Network;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -10,6 +9,8 @@ namespace Barotrauma
|
||||
{
|
||||
partial class MultiPlayerCampaign : CampaignMode
|
||||
{
|
||||
public bool SuppressStateSending = false;
|
||||
|
||||
private UInt16 startWatchmanID, endWatchmanID;
|
||||
|
||||
public static GUIComponent StartCampaignSetup( IEnumerable<Submarine> submarines, IEnumerable<string> saveFiles)
|
||||
@@ -129,7 +130,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public void ClientWrite(NetBuffer msg)
|
||||
public void ClientWrite(IWriteMessage msg)
|
||||
{
|
||||
System.Diagnostics.Debug.Assert(map.Locations.Count < UInt16.MaxValue);
|
||||
|
||||
@@ -147,7 +148,7 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
//static because we may need to instantiate the campaign if it hasn't been done yet
|
||||
public static void ClientRead(NetBuffer msg)
|
||||
public static void ClientRead(IReadMessage msg)
|
||||
{
|
||||
byte campaignID = msg.ReadByte();
|
||||
UInt16 updateID = msg.ReadUInt16();
|
||||
@@ -213,6 +214,8 @@ namespace Barotrauma
|
||||
|
||||
if (NetIdUtils.IdMoreRecent(updateID, campaign.lastUpdateID))
|
||||
{
|
||||
campaign.SuppressStateSending = true;
|
||||
|
||||
campaign.Map.SetLocation(currentLocIndex == UInt16.MaxValue ? -1 : currentLocIndex);
|
||||
campaign.Map.SelectLocation(selectedLocIndex == UInt16.MaxValue ? -1 : selectedLocIndex);
|
||||
campaign.Map.SelectMission(selectedMissionIndex);
|
||||
@@ -236,6 +239,8 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
campaign.lastUpdateID = updateID;
|
||||
|
||||
campaign.SuppressStateSending = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -218,7 +218,7 @@ namespace Barotrauma.Tutorials
|
||||
}
|
||||
}
|
||||
yield return null;
|
||||
} while (!captain_sonar.IsActive);
|
||||
} while (captain_sonar.CurrentMode != Sonar.Mode.Active);
|
||||
do { yield return null; } while (Vector2.Distance(Submarine.MainSub.WorldPosition, Level.Loaded.EndPosition) > 4000f);
|
||||
RemoveCompletedObjective(segments[5]);
|
||||
yield return new WaitForSeconds(4f, false);
|
||||
|
||||
@@ -73,6 +73,7 @@ namespace Barotrauma.Tutorials
|
||||
private Character mechanic;
|
||||
private Sprite mechanic_repairIcon;
|
||||
private Color mechanic_repairIconColor;
|
||||
private Sprite mechanic_weldIcon;
|
||||
|
||||
public MechanicTutorial(XElement element) : base(element)
|
||||
{
|
||||
@@ -97,6 +98,7 @@ namespace Barotrauma.Tutorials
|
||||
var repairOrder = Order.PrefabList.Find(order => order.AITag == "repairsystems");
|
||||
mechanic_repairIcon = repairOrder.SymbolSprite;
|
||||
mechanic_repairIconColor = repairOrder.Color;
|
||||
mechanic_weldIcon = new Sprite("Content/UI/IconAtlas.png", new Rectangle(1, 256, 127, 127), new Vector2(0.5f, 0.5f));
|
||||
|
||||
// Other tutorial items
|
||||
tutorial_securityFinalDoorLight = Item.ItemList.Find(i => i.HasTag("tutorial_securityfinaldoorlight")).GetComponent<LightComponent>();
|
||||
@@ -309,7 +311,7 @@ namespace Barotrauma.Tutorials
|
||||
yield return null;
|
||||
} while (!mechanic.HasEquippedItem("divingmask") || !mechanic.HasEquippedItem("weldingtool")); // Wait until equipped
|
||||
SetDoorAccess(mechanic_secondDoor, mechanic_secondDoorLight, true);
|
||||
mechanic.AddActiveObjectiveEntity(mechanic_brokenWall_1, mechanic_repairIcon, mechanic_repairIconColor);
|
||||
mechanic.AddActiveObjectiveEntity(mechanic_brokenWall_1, mechanic_weldIcon, mechanic_repairIconColor);
|
||||
do { yield return null; } while (WallHasDamagedSections(mechanic_brokenWall_1)); // Highlight until repaired
|
||||
mechanic.RemoveActiveObjectiveEntity(mechanic_brokenWall_1);
|
||||
RemoveCompletedObjective(segments[2]);
|
||||
@@ -443,10 +445,10 @@ namespace Barotrauma.Tutorials
|
||||
{
|
||||
HighlightInventorySlot(mechanic_fabricator.OutputContainer.Inventory, "extinguisher", highlightColor, .5f, .5f, 0f);
|
||||
|
||||
for (int i = 0; i < mechanic.Inventory.slots.Length; i++)
|
||||
/*for (int i = 0; i < mechanic.Inventory.slots.Length; i++)
|
||||
{
|
||||
if (mechanic.Inventory.Items[i] == null) HighlightInventorySlot(mechanic.Inventory, i, highlightColor, .5f, .5f, 0f);
|
||||
}
|
||||
}*/
|
||||
}
|
||||
else if (mechanic_fabricator.InputContainer.Inventory.FindItemByIdentifier("aluminium") != null && mechanic_fabricator.InputContainer.Inventory.FindItemByIdentifier("sodium") != null && !mechanic_fabricator.IsActive)
|
||||
{
|
||||
@@ -521,7 +523,7 @@ namespace Barotrauma.Tutorials
|
||||
SetDoorAccess(tutorial_mechanicFinalDoor, tutorial_mechanicFinalDoorLight, true);
|
||||
|
||||
// Room 7
|
||||
mechanic.AddActiveObjectiveEntity(mechanic_brokenWall_2, mechanic_repairIcon, mechanic_repairIconColor);
|
||||
mechanic.AddActiveObjectiveEntity(mechanic_brokenWall_2, mechanic_weldIcon, mechanic_repairIconColor);
|
||||
do { yield return null; } while (WallHasDamagedSections(mechanic_brokenWall_2));
|
||||
mechanic.RemoveActiveObjectiveEntity(mechanic_brokenWall_2);
|
||||
TriggerTutorialSegment(9, GameMain.Config.KeyBind(InputType.Use)); // Repairing machinery (pump)
|
||||
|
||||
@@ -305,10 +305,17 @@ namespace Barotrauma.Tutorials
|
||||
do
|
||||
{
|
||||
float distance = Vector2.Distance(officer_coilgunPeriscope.WorldPosition, officer_hammerhead.WorldPosition);
|
||||
if (distance > originalDistance * 1.5f)
|
||||
{
|
||||
// Don't let the Hammerhead go too far.
|
||||
officer_hammerhead.TeleportTo(officer_hammerheadSpawnPos + new Vector2(0, -1000));
|
||||
}
|
||||
if (distance > originalDistance)
|
||||
{
|
||||
// Don't let the Hammerhead go too far from the periscope.
|
||||
officer_hammerhead.TeleportTo(officer_hammerheadSpawnPos);
|
||||
// Ensure that the Hammerhead targets the player
|
||||
officer_hammerhead.AIController.SelectTarget(officer.AiTarget);
|
||||
var ai = officer_hammerhead.AIController as EnemyAIController;
|
||||
ai.sight = 2.0f;
|
||||
}
|
||||
yield return null;
|
||||
}
|
||||
|
||||
@@ -110,21 +110,33 @@ namespace Barotrauma
|
||||
{
|
||||
infoFrameContent.ClearChildren();
|
||||
|
||||
var paddedFrame = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.95f), infoFrameContent.RectTransform))
|
||||
var isTraitor = GameMain.Client?.Character?.IsTraitor ?? false;
|
||||
|
||||
var missionFrame = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, isTraitor ? 0.95f : 0.45f), infoFrameContent.RectTransform))
|
||||
{
|
||||
RelativeSpacing = 0.05f
|
||||
};
|
||||
|
||||
if (Mission == null)
|
||||
if (Mission != null)
|
||||
{
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.1f), paddedFrame.RectTransform, Anchor.TopCenter), TextManager.Get("NoMission"));
|
||||
return;
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), missionFrame.RectTransform), Mission.Name, font: GUI.LargeFont);
|
||||
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), missionFrame.RectTransform), TextManager.GetWithVariable("MissionReward", "[reward]", Mission.Reward.ToString()));
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), missionFrame.RectTransform), Mission.Description, wrap: true);
|
||||
}
|
||||
else
|
||||
{
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), missionFrame.RectTransform, Anchor.TopCenter), TextManager.Get("NoMission"), font: GUI.LargeFont);
|
||||
}
|
||||
if (isTraitor)
|
||||
{
|
||||
var traitorFrame = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.45f), infoFrameContent.RectTransform, Anchor.BottomLeft))
|
||||
{
|
||||
RelativeSpacing = 0.05f
|
||||
};
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), traitorFrame.RectTransform), TextManager.Get("Traitors"), font: GUI.LargeFont);
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), traitorFrame.RectTransform), GameMain.Client.Character.TraitorCurrentObjective, wrap: true);
|
||||
}
|
||||
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.1f), paddedFrame.RectTransform), Mission.Name, font: GUI.LargeFont);
|
||||
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.1f), paddedFrame.RectTransform), TextManager.GetWithVariable("MissionReward", "[reward]", Mission.Reward.ToString()));
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), paddedFrame.RectTransform), Mission.Description, wrap: true);
|
||||
}
|
||||
|
||||
public void AddToGUIUpdateList()
|
||||
|
||||
@@ -57,10 +57,11 @@ namespace Barotrauma
|
||||
var infoText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), infoTextBox.Content.RectTransform),
|
||||
summaryText, wrap: true);
|
||||
|
||||
GUIComponent endText = null;
|
||||
if (!string.IsNullOrWhiteSpace(endMessage))
|
||||
{
|
||||
var endText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), infoTextBox.Content.RectTransform),
|
||||
endMessage, wrap: true);
|
||||
endText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), infoTextBox.Content.RectTransform),
|
||||
TextManager.GetServerMessage(endMessage), wrap: true);
|
||||
}
|
||||
|
||||
//don't show the mission info if the mission was not completed and there's no localized "mission failed" text available
|
||||
@@ -70,7 +71,9 @@ namespace Barotrauma
|
||||
if (!string.IsNullOrEmpty(message))
|
||||
{
|
||||
//spacing
|
||||
new GUIFrame(new RectTransform(new Vector2(1.0f, 0.1f), infoTextBox.Content.RectTransform), style: null);
|
||||
var spacingTransform = new RectTransform(new Vector2(1.0f, 0.1f), infoTextBox.Content.RectTransform);
|
||||
|
||||
new GUIFrame(spacingTransform, style: null);
|
||||
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), infoTextBox.Content.RectTransform),
|
||||
TextManager.AddPunctuation(':', TextManager.Get("Mission"), GameMain.GameSession.Mission.Name),
|
||||
@@ -86,12 +89,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (GUIComponent child in infoTextBox.Content.Children)
|
||||
{
|
||||
child.CanBeFocused = false;
|
||||
}
|
||||
|
||||
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), paddedFrame.RectTransform),
|
||||
TextManager.Get("RoundSummaryCrewStatus"), font: GUI.LargeFont);
|
||||
|
||||
@@ -166,6 +164,16 @@ namespace Barotrauma
|
||||
UserData = "buttonarea"
|
||||
};
|
||||
|
||||
paddedFrame.Recalculate();
|
||||
foreach (GUIComponent child in infoTextBox.Content.Children)
|
||||
{
|
||||
child.CanBeFocused = false;
|
||||
if (child is GUITextBlock textBlock)
|
||||
{
|
||||
textBlock.CalculateHeightFromText();
|
||||
}
|
||||
}
|
||||
|
||||
return frame;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,11 +73,23 @@ namespace Barotrauma
|
||||
|
||||
public void CreateSettingsFrame(Tab selectedTab = Tab.Graphics)
|
||||
{
|
||||
settingsFrame = new GUIFrame(new RectTransform(new Vector2(0.8f, 0.8f), GUI.Canvas, Anchor.Center));
|
||||
RectTransform settingsHolder = null;
|
||||
|
||||
if (Screen.Selected == GameMain.MainMenuScreen)
|
||||
{
|
||||
settingsFrame = new GUIFrame(new RectTransform(new Vector2(0.8f, 0.8f), GUI.Canvas, Anchor.Center));
|
||||
settingsHolder = settingsFrame.RectTransform;
|
||||
}
|
||||
else
|
||||
{
|
||||
settingsFrame = new GUIFrame(new RectTransform(Vector2.One, GUI.Canvas), style: null, color: Color.Black * 0.5f);
|
||||
var settingsFrameContent = new GUIFrame(new RectTransform(new Vector2(0.8f, 0.8f), settingsFrame.RectTransform, Anchor.Center));
|
||||
settingsHolder = settingsFrameContent.RectTransform;
|
||||
}
|
||||
|
||||
Vector2 tickBoxScale = Vector2.One * 0.05f;
|
||||
|
||||
var settingsFramePadding = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.9f), settingsFrame.RectTransform, Anchor.TopCenter) { RelativeOffset = new Vector2(0.0f, 0.05f) }) { RelativeSpacing = 0.01f, IsHorizontal = true };
|
||||
var settingsFramePadding = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.9f), settingsHolder, Anchor.TopCenter) { RelativeOffset = new Vector2(0.0f, 0.05f) }) { RelativeSpacing = 0.01f, IsHorizontal = true };
|
||||
|
||||
/// General tab --------------------------------------------------------------
|
||||
|
||||
@@ -104,6 +116,10 @@ namespace Barotrauma
|
||||
OnSelected = SelectContentPackage,
|
||||
Selected = SelectedContentPackages.Contains(contentPackage)
|
||||
};
|
||||
if (contentPackage.CorePackage)
|
||||
{
|
||||
tickBox.TextColor = Color.White;
|
||||
}
|
||||
if (!contentPackage.IsCompatible())
|
||||
{
|
||||
tickBox.TextColor = Color.Red;
|
||||
@@ -251,11 +267,11 @@ namespace Barotrauma
|
||||
Selected = VSyncEnabled
|
||||
};
|
||||
|
||||
//TODO: remove hardcoded texts after the texts have been added to localization
|
||||
|
||||
GUITickBox pauseOnFocusLostBox = new GUITickBox(new RectTransform(tickBoxScale, leftColumn.RectTransform, scaleBasis: ScaleBasis.BothHeight),
|
||||
TextManager.Get("PauseOnFocusLost", returnNull: true) ?? "Pause on focus lost");
|
||||
TextManager.Get("PauseOnFocusLost"));
|
||||
pauseOnFocusLostBox.Selected = PauseOnFocusLost;
|
||||
pauseOnFocusLostBox.ToolTip = TextManager.Get("PauseOnFocusLostToolTip", returnNull: true) ?? "Pauses the game when its window is not in focus. Note that the game won't be paused when a multiplayer session is active.";
|
||||
pauseOnFocusLostBox.ToolTip = TextManager.Get("PauseOnFocusLostToolTip");
|
||||
pauseOnFocusLostBox.OnSelected = (tickBox) =>
|
||||
{
|
||||
PauseOnFocusLost = tickBox.Selected;
|
||||
@@ -377,12 +393,12 @@ namespace Barotrauma
|
||||
|
||||
/// Audio tab ----------------------------------------------------------------
|
||||
|
||||
var audioSliders = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.95f), tabs[(int)Tab.Audio].RectTransform, Anchor.TopCenter)
|
||||
var audioSliders = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.3f), tabs[(int)Tab.Audio].RectTransform, Anchor.TopCenter)
|
||||
{ RelativeOffset = new Vector2(0.0f, 0.02f) })
|
||||
{ RelativeSpacing = 0.01f };
|
||||
|
||||
GUITextBlock soundVolumeText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), audioSliders.RectTransform), TextManager.Get("SoundVolume"));
|
||||
GUIScrollBar soundScrollBar = new GUIScrollBar(new RectTransform(new Vector2(1.0f, 0.05f), audioSliders.RectTransform),
|
||||
GUITextBlock soundVolumeText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.15f), audioSliders.RectTransform), TextManager.Get("SoundVolume"));
|
||||
GUIScrollBar soundScrollBar = new GUIScrollBar(new RectTransform(new Vector2(1.0f, 0.15f), audioSliders.RectTransform),
|
||||
barSize: 0.05f)
|
||||
{
|
||||
UserData = soundVolumeText,
|
||||
@@ -397,8 +413,8 @@ namespace Barotrauma
|
||||
};
|
||||
soundScrollBar.OnMoved(soundScrollBar, soundScrollBar.BarScroll);
|
||||
|
||||
GUITextBlock musicVolumeText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), audioSliders.RectTransform), TextManager.Get("MusicVolume"));
|
||||
GUIScrollBar musicScrollBar = new GUIScrollBar(new RectTransform(new Vector2(1.0f, 0.05f), audioSliders.RectTransform),
|
||||
GUITextBlock musicVolumeText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.15f), audioSliders.RectTransform), TextManager.Get("MusicVolume"));
|
||||
GUIScrollBar musicScrollBar = new GUIScrollBar(new RectTransform(new Vector2(1.0f, 0.15f), audioSliders.RectTransform),
|
||||
barSize: 0.05f)
|
||||
{
|
||||
UserData = musicVolumeText,
|
||||
@@ -413,8 +429,8 @@ namespace Barotrauma
|
||||
};
|
||||
musicScrollBar.OnMoved(musicScrollBar, musicScrollBar.BarScroll);
|
||||
|
||||
GUITextBlock voiceChatVolumeText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), audioSliders.RectTransform), TextManager.Get("VoiceChatVolume"));
|
||||
GUIScrollBar voiceChatScrollBar = new GUIScrollBar(new RectTransform(new Vector2(1.0f, 0.05f), audioSliders.RectTransform),
|
||||
GUITextBlock voiceChatVolumeText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.15f), audioSliders.RectTransform), TextManager.Get("VoiceChatVolume"));
|
||||
GUIScrollBar voiceChatScrollBar = new GUIScrollBar(new RectTransform(new Vector2(1.0f, 0.15f), audioSliders.RectTransform),
|
||||
barSize: 0.05f)
|
||||
{
|
||||
UserData = voiceChatVolumeText,
|
||||
@@ -429,7 +445,17 @@ namespace Barotrauma
|
||||
};
|
||||
voiceChatScrollBar.OnMoved(voiceChatScrollBar, voiceChatScrollBar.BarScroll);
|
||||
|
||||
GUITickBox muteOnFocusLostBox = new GUITickBox(new RectTransform(tickBoxScale, audioSliders.RectTransform, scaleBasis: ScaleBasis.BothHeight), TextManager.Get("MuteOnFocusLost"));
|
||||
var leftTickBoxes = new GUILayoutGroup(new RectTransform(new Vector2(0.28f, 0.06f), tabs[(int)Tab.Audio].RectTransform, Anchor.TopLeft)
|
||||
{ RelativeOffset = new Vector2(0.02f, 0.32f) })
|
||||
{ RelativeSpacing = 0.01f };
|
||||
var centerTickBoxes = new GUILayoutGroup(new RectTransform(new Vector2(0.4f, 0.06f), tabs[(int)Tab.Audio].RectTransform, Anchor.TopLeft)
|
||||
{ RelativeOffset = new Vector2(0.3f, 0.32f) })
|
||||
{ RelativeSpacing = 0.01f };
|
||||
var rightTickBoxes = new GUILayoutGroup(new RectTransform(new Vector2(0.3f, 0.06f), tabs[(int)Tab.Audio].RectTransform, Anchor.TopRight)
|
||||
{ RelativeOffset = new Vector2(0.02f, 0.32f) })
|
||||
{ RelativeSpacing = 0.01f };
|
||||
|
||||
GUITickBox muteOnFocusLostBox = new GUITickBox(new RectTransform(tickBoxScale / 0.06f, leftTickBoxes.RectTransform, scaleBasis: ScaleBasis.BothHeight), TextManager.Get("MuteOnFocusLost"));
|
||||
muteOnFocusLostBox.Selected = MuteOnFocusLost;
|
||||
muteOnFocusLostBox.ToolTip = TextManager.Get("MuteOnFocusLostToolTip");
|
||||
muteOnFocusLostBox.OnSelected = (tickBox) =>
|
||||
@@ -439,7 +465,31 @@ namespace Barotrauma
|
||||
return true;
|
||||
};
|
||||
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), audioSliders.RectTransform), TextManager.Get("VoiceChat"));
|
||||
GUITickBox dynamicRangeCompressionTickBox = new GUITickBox(new RectTransform(tickBoxScale / 0.06f, centerTickBoxes.RectTransform, scaleBasis: ScaleBasis.BothHeight), TextManager.Get("DynamicRangeCompression"));
|
||||
dynamicRangeCompressionTickBox.Selected = DynamicRangeCompressionEnabled;
|
||||
dynamicRangeCompressionTickBox.ToolTip = TextManager.Get("DynamicRangeCompressionToolTip");
|
||||
dynamicRangeCompressionTickBox.OnSelected = (tickBox) =>
|
||||
{
|
||||
DynamicRangeCompressionEnabled = tickBox.Selected;
|
||||
UnsavedSettings = true;
|
||||
return true;
|
||||
};
|
||||
|
||||
GUITickBox voipAttenuationTickBox = new GUITickBox(new RectTransform(tickBoxScale / 0.06f, rightTickBoxes.RectTransform, scaleBasis: ScaleBasis.BothHeight), TextManager.Get("VoipAttenuation"));
|
||||
voipAttenuationTickBox.Selected = VoipAttenuationEnabled;
|
||||
voipAttenuationTickBox.ToolTip = TextManager.Get("VoipAttenuationToolTip");
|
||||
voipAttenuationTickBox.OnSelected = (tickBox) =>
|
||||
{
|
||||
VoipAttenuationEnabled = tickBox.Selected;
|
||||
UnsavedSettings = true;
|
||||
return true;
|
||||
};
|
||||
|
||||
var voipSettings = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.4f), tabs[(int)Tab.Audio].RectTransform, Anchor.TopCenter)
|
||||
{ RelativeOffset = new Vector2(0.0f, 0.38f) })
|
||||
{ RelativeSpacing = 0.01f };
|
||||
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.15f), voipSettings.RectTransform), TextManager.Get("VoiceChat"));
|
||||
|
||||
IList<string> deviceNames = Alc.GetStringList((IntPtr)null, Alc.CaptureDeviceSpecifier);
|
||||
foreach (string name in deviceNames)
|
||||
@@ -447,7 +497,7 @@ namespace Barotrauma
|
||||
DebugConsole.NewMessage(name + " " + name.Length.ToString(), Color.Lime);
|
||||
}
|
||||
|
||||
GUITickBox directionalVoiceChat = new GUITickBox(new RectTransform(tickBoxScale, audioSliders.RectTransform, scaleBasis: ScaleBasis.BothHeight), TextManager.Get("DirectionalVoiceChat"));
|
||||
GUITickBox directionalVoiceChat = new GUITickBox(new RectTransform(tickBoxScale / 0.4f, voipSettings.RectTransform, scaleBasis: ScaleBasis.BothHeight), TextManager.Get("DirectionalVoiceChat"));
|
||||
directionalVoiceChat.Selected = UseDirectionalVoiceChat;
|
||||
directionalVoiceChat.ToolTip = TextManager.Get("DirectionalVoiceChatToolTip");
|
||||
directionalVoiceChat.OnSelected = (tickBox) =>
|
||||
@@ -466,7 +516,7 @@ namespace Barotrauma
|
||||
VoiceSetting = VoiceMode.Disabled;
|
||||
}
|
||||
#if (!OSX)
|
||||
var deviceList = new GUIDropDown(new RectTransform(new Vector2(1.0f, 0.05f), audioSliders.RectTransform), TrimAudioDeviceName(VoiceCaptureDevice), deviceNames.Count);
|
||||
var deviceList = new GUIDropDown(new RectTransform(new Vector2(1.0f, 0.15f), voipSettings.RectTransform), TrimAudioDeviceName(VoiceCaptureDevice), deviceNames.Count);
|
||||
if (deviceNames?.Count > 0)
|
||||
{
|
||||
foreach (string name in deviceNames)
|
||||
@@ -490,7 +540,7 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
#else
|
||||
var defaultDeviceGroup = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.1f), audioSliders.RectTransform), true, Anchor.CenterLeft);
|
||||
var defaultDeviceGroup = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.3f), voipSettings.RectTransform), true, Anchor.CenterLeft);
|
||||
var currentDeviceTextBlock = new GUITextBlock(new RectTransform(new Vector2(.7f, 0.75f), null),
|
||||
TextManager.AddPunctuation(':', TextManager.Get("CurrentDevice"), TrimAudioDeviceName(VoiceCaptureDevice)))
|
||||
{
|
||||
@@ -526,13 +576,12 @@ namespace Barotrauma
|
||||
|
||||
currentDeviceTextBlock.RectTransform.Parent = defaultDeviceGroup.RectTransform;
|
||||
#endif
|
||||
//var radioButtonFrame = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.12f), audioSliders.RectTransform));
|
||||
|
||||
GUIRadioButtonGroup voiceMode = new GUIRadioButtonGroup();
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
string langStr = "VoiceMode." + ((VoiceMode)i).ToString();
|
||||
var tick = new GUITickBox(new RectTransform(tickBoxScale, audioSliders.RectTransform, scaleBasis: ScaleBasis.BothHeight), TextManager.Get(langStr))
|
||||
var tick = new GUITickBox(new RectTransform(tickBoxScale / 0.4f, voipSettings.RectTransform, scaleBasis: ScaleBasis.BothHeight), TextManager.Get(langStr))
|
||||
{
|
||||
ToolTip = TextManager.Get(langStr + "ToolTip")
|
||||
};
|
||||
@@ -540,8 +589,8 @@ namespace Barotrauma
|
||||
voiceMode.AddRadioButton((VoiceMode)i, tick);
|
||||
}
|
||||
|
||||
var micVolumeText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), audioSliders.RectTransform), TextManager.Get("MicrophoneVolume"));
|
||||
var micVolumeSlider = new GUIScrollBar(new RectTransform(new Vector2(1.0f, 0.05f), audioSliders.RectTransform),
|
||||
var micVolumeText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.15f), voipSettings.RectTransform), TextManager.Get("MicrophoneVolume"));
|
||||
var micVolumeSlider = new GUIScrollBar(new RectTransform(new Vector2(1.0f, 0.15f), voipSettings.RectTransform),
|
||||
barSize: 0.05f)
|
||||
{
|
||||
UserData = micVolumeText,
|
||||
@@ -559,7 +608,7 @@ namespace Barotrauma
|
||||
micVolumeSlider.OnMoved(micVolumeSlider, micVolumeSlider.BarScroll);
|
||||
|
||||
|
||||
var extraVoiceSettingsContainer = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.2f), audioSliders.RectTransform, Anchor.BottomCenter), style: null);
|
||||
var extraVoiceSettingsContainer = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.6f), voipSettings.RectTransform, Anchor.BottomCenter), style: null);
|
||||
|
||||
var voiceInputContainer = new GUILayoutGroup(new RectTransform(Vector2.One, extraVoiceSettingsContainer.RectTransform, Anchor.BottomCenter));
|
||||
new GUITextBlock(new RectTransform(new Vector2(0.6f, 0.25f), voiceInputContainer.RectTransform), TextManager.Get("InputType.Voice"));
|
||||
|
||||
@@ -107,6 +107,17 @@ namespace Barotrauma
|
||||
SetSlotPositions(layout);
|
||||
}
|
||||
|
||||
protected override ItemInventory GetActiveEquippedSubInventory(int slotIndex)
|
||||
{
|
||||
var item = Items[slotIndex];
|
||||
if (item == null) return null;
|
||||
|
||||
var container = item.GetComponent<ItemContainer>();
|
||||
if (container == null || !container.KeepOpenWhenEquipped || !character.HasEquippedItem(container.Item)) return null;
|
||||
|
||||
return container.Inventory;
|
||||
}
|
||||
|
||||
protected override void PutItem(Item item, int i, Character user, bool removeItem = true, bool createNetworkEvent = true)
|
||||
{
|
||||
base.PutItem(item, i, user, removeItem, createNetworkEvent);
|
||||
@@ -456,7 +467,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
List<SlotReference> hideSubInventories = new List<SlotReference>();
|
||||
foreach (var highlightedSubInventorySlot in highlightedSubInventorySlots)
|
||||
{
|
||||
@@ -465,6 +476,8 @@ namespace Barotrauma
|
||||
UpdateSubInventory(deltaTime, highlightedSubInventorySlot.SlotIndex, cam);
|
||||
}
|
||||
|
||||
if (!highlightedSubInventorySlot.Inventory.IsInventoryHoverAvailable(character, null)) continue;
|
||||
|
||||
Rectangle hoverArea = GetSubInventoryHoverArea(highlightedSubInventorySlot);
|
||||
if (highlightedSubInventorySlot.Inventory?.slots == null || (!hoverArea.Contains(PlayerInput.MousePosition)))
|
||||
{
|
||||
@@ -476,35 +489,16 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
if (doubleClickedItem != null)
|
||||
{
|
||||
QuickUseItem(doubleClickedItem, true, true, true);
|
||||
}
|
||||
|
||||
//activate the subinventory of the currently selected slot
|
||||
if (selectedSlot?.ParentInventory == this)
|
||||
{
|
||||
var subInventory = GetSubInventory(selectedSlot.SlotIndex);
|
||||
if (subInventory != null)
|
||||
if (subInventory != null && subInventory.IsInventoryHoverAvailable(character, null))
|
||||
{
|
||||
selectedSlot.Inventory = subInventory;
|
||||
if (!highlightedSubInventorySlots.Any(s => s.Inventory == subInventory))
|
||||
{
|
||||
var slot = selectedSlot;
|
||||
highlightedSubInventorySlots.Add(selectedSlot);
|
||||
UpdateSubInventory(deltaTime, selectedSlot.SlotIndex, cam);
|
||||
|
||||
//hide previously opened subinventories if this one overlaps with them
|
||||
Rectangle hoverArea = GetSubInventoryHoverArea(slot);
|
||||
foreach (SlotReference highlightedSubInventorySlot in highlightedSubInventorySlots)
|
||||
{
|
||||
if (highlightedSubInventorySlot == slot) continue;
|
||||
if (hoverArea.Intersects(GetSubInventoryHoverArea(highlightedSubInventorySlot)))
|
||||
{
|
||||
hideSubInventories.Add(highlightedSubInventorySlot);
|
||||
highlightedSubInventorySlot.Inventory.HideTimer = 0.0f;
|
||||
}
|
||||
}
|
||||
ShowSubInventory(selectedSlot, deltaTime, cam, hideSubInventories, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -513,66 +507,49 @@ namespace Barotrauma
|
||||
{
|
||||
if (subInventorySlot.Inventory == null) continue;
|
||||
subInventorySlot.Inventory.HideTimer -= deltaTime;
|
||||
if (subInventorySlot.Inventory.HideTimer <= 0.0f)
|
||||
if (subInventorySlot.Inventory.HideTimer < 0.25f)
|
||||
{
|
||||
highlightedSubInventorySlots.Remove(subInventorySlot);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < capacity; i++)
|
||||
|
||||
if (character.SelectedCharacter == null) // Permanently open subinventories only available when the default UI layout is in use -> not when grabbing characters
|
||||
{
|
||||
if (Items[i] != null && Items[i].AllowedSlots.Any(a => a != InvSlotType.Any))
|
||||
for (int i = 0; i < capacity; i++)
|
||||
{
|
||||
slots[i].EquipButtonState = slots[i].EquipButtonRect.Contains(PlayerInput.MousePosition) ?
|
||||
GUIComponent.ComponentState.Hover : GUIComponent.ComponentState.None;
|
||||
if (PlayerInput.LeftButtonHeld() && PlayerInput.RightButtonHeld())
|
||||
var item = Items[i];
|
||||
if (item != null)
|
||||
{
|
||||
slots[i].EquipButtonState = GUIComponent.ComponentState.None;
|
||||
}
|
||||
|
||||
if (slots[i].EquipButtonState != GUIComponent.ComponentState.Hover)
|
||||
{
|
||||
slots[i].QuickUseTimer = Math.Max(0.0f, slots[i].QuickUseTimer - deltaTime * 5.0f);
|
||||
continue;
|
||||
}
|
||||
|
||||
var quickUseAction = GetQuickUseAction(Items[i], allowEquip: true, allowInventorySwap: false, allowApplyTreatment: false);
|
||||
slots[i].QuickUseButtonToolTip = quickUseAction == QuickUseAction.None ?
|
||||
"" : TextManager.Get("QuickUseAction." + quickUseAction.ToString());
|
||||
|
||||
//equipped item that can't be put in the inventory, use delayed dropping
|
||||
if (quickUseAction == QuickUseAction.Drop)
|
||||
{
|
||||
slots[i].QuickUseButtonToolTip =
|
||||
TextManager.Get("QuickUseAction.HoldToUnequip", returnNull: true) ??
|
||||
(GameMain.Config.Language == "English" ? "Hold to unequip" : TextManager.Get("QuickUseAction.Unequip"));
|
||||
|
||||
if (PlayerInput.LeftButtonHeld())
|
||||
if (HideSlot(i)) continue;
|
||||
if (character.HasEquippedItem(item)) // Keep a subinventory display open permanently when the container is equipped
|
||||
{
|
||||
slots[i].QuickUseTimer = Math.Max(0.1f, slots[i].QuickUseTimer + deltaTime);
|
||||
if (slots[i].QuickUseTimer >= 1.0f)
|
||||
var itemContainer = item.GetComponent<ItemContainer>();
|
||||
if (itemContainer != null && itemContainer.KeepOpenWhenEquipped && !highlightedSubInventorySlots.Any(s => s.Inventory == itemContainer.Inventory))
|
||||
{
|
||||
Items[i].Drop(Character.Controlled);
|
||||
GUI.PlayUISound(GUISoundType.DropItem);
|
||||
ShowSubInventory(new SlotReference(this, slots[i], i, false, itemContainer.Inventory), deltaTime, cam, hideSubInventories, true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
slots[i].QuickUseTimer = Math.Max(0.0f, slots[i].QuickUseTimer - deltaTime * 5.0f);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (PlayerInput.LeftButtonDown()) slots[i].EquipButtonState = GUIComponent.ComponentState.Pressed;
|
||||
if (PlayerInput.LeftButtonClicked())
|
||||
{
|
||||
QuickUseItem(Items[i], allowEquip: true, allowInventorySwap: false, allowApplyTreatment: false);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (doubleClickedItem != null)
|
||||
{
|
||||
QuickUseItem(doubleClickedItem, true, true, true);
|
||||
}
|
||||
|
||||
for (int i = 0; i < capacity; i++)
|
||||
{
|
||||
var item = Items[i];
|
||||
if (item != null)
|
||||
{
|
||||
var slot = slots[i];
|
||||
if (item.AllowedSlots.Any(a => a != InvSlotType.Any))
|
||||
{
|
||||
HandleButtonEquipStates(item, slot, deltaTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//cancel dragging if too far away from the container of the dragged item
|
||||
if (draggingItem != null)
|
||||
@@ -603,6 +580,89 @@ namespace Barotrauma
|
||||
|
||||
doubleClickedItem = null;
|
||||
}
|
||||
|
||||
private void HandleButtonEquipStates(Item item, InventorySlot slot, float deltaTime)
|
||||
{
|
||||
slot.EquipButtonState = slot.EquipButtonRect.Contains(PlayerInput.MousePosition) ?
|
||||
GUIComponent.ComponentState.Hover : GUIComponent.ComponentState.None;
|
||||
if (PlayerInput.LeftButtonHeld() && PlayerInput.RightButtonHeld())
|
||||
{
|
||||
slot.EquipButtonState = GUIComponent.ComponentState.None;
|
||||
}
|
||||
|
||||
if (slot.EquipButtonState != GUIComponent.ComponentState.Hover)
|
||||
{
|
||||
slot.QuickUseTimer = Math.Max(0.0f, slot.QuickUseTimer - deltaTime * 5.0f);
|
||||
return;
|
||||
}
|
||||
|
||||
var quickUseAction = GetQuickUseAction(item, allowEquip: true, allowInventorySwap: false, allowApplyTreatment: false);
|
||||
slot.QuickUseButtonToolTip = quickUseAction == QuickUseAction.None ?
|
||||
"" : TextManager.Get("QuickUseAction." + quickUseAction.ToString());
|
||||
|
||||
//equipped item that can't be put in the inventory, use delayed dropping
|
||||
if (quickUseAction == QuickUseAction.Drop)
|
||||
{
|
||||
slot.QuickUseButtonToolTip =
|
||||
TextManager.Get("QuickUseAction.HoldToUnequip", returnNull: true) ??
|
||||
(GameMain.Config.Language == "English" ? "Hold to unequip" : TextManager.Get("QuickUseAction.Unequip"));
|
||||
|
||||
if (PlayerInput.LeftButtonHeld())
|
||||
{
|
||||
slot.QuickUseTimer = Math.Max(0.1f, slot.QuickUseTimer + deltaTime);
|
||||
if (slot.QuickUseTimer >= 1.0f)
|
||||
{
|
||||
item.Drop(Character.Controlled);
|
||||
GUI.PlayUISound(GUISoundType.DropItem);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
slot.QuickUseTimer = Math.Max(0.0f, slot.QuickUseTimer - deltaTime * 5.0f);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (PlayerInput.LeftButtonDown()) slot.EquipButtonState = GUIComponent.ComponentState.Pressed;
|
||||
if (PlayerInput.LeftButtonClicked())
|
||||
{
|
||||
QuickUseItem(item, allowEquip: true, allowInventorySwap: false, allowApplyTreatment: false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ShowSubInventory(SlotReference slotRef, float deltaTime, Camera cam, List<SlotReference> hideSubInventories, bool isEquippedSubInventory)
|
||||
{
|
||||
Rectangle hoverArea = GetSubInventoryHoverArea(slotRef);
|
||||
if (isEquippedSubInventory)
|
||||
{
|
||||
foreach (SlotReference highlightedSubInventorySlot in highlightedSubInventorySlots)
|
||||
{
|
||||
if (highlightedSubInventorySlot == slotRef) continue;
|
||||
if (hoverArea.Intersects(GetSubInventoryHoverArea(highlightedSubInventorySlot)))
|
||||
{
|
||||
return; // If an equipped one intersects with a currently active hover one, do not open
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
slotRef.Inventory.OpenState = isEquippedSubInventory ? 1f : 0f; // Reset animation when initially equipped
|
||||
|
||||
highlightedSubInventorySlots.Add(slotRef);
|
||||
slotRef.Inventory.HideTimer = 1f;
|
||||
UpdateSubInventory(deltaTime, slotRef.SlotIndex, cam);
|
||||
|
||||
//hide previously opened subinventories if this one overlaps with them
|
||||
foreach (SlotReference highlightedSubInventorySlot in highlightedSubInventorySlots)
|
||||
{
|
||||
if (highlightedSubInventorySlot == slotRef) continue;
|
||||
if (hoverArea.Intersects(GetSubInventoryHoverArea(highlightedSubInventorySlot)))
|
||||
{
|
||||
hideSubInventories.Add(highlightedSubInventorySlot);
|
||||
highlightedSubInventorySlot.Inventory.HideTimer = 0.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void AssignQuickUseNumKeys()
|
||||
{
|
||||
@@ -633,14 +693,34 @@ namespace Barotrauma
|
||||
if (item.ParentInventory != this)
|
||||
{
|
||||
//in another inventory -> attempt to place in the character's inventory
|
||||
if (item.ParentInventory.Locked)
|
||||
if (item.ParentInventory.Locked || item.ParentInventory == null)
|
||||
{
|
||||
return QuickUseAction.None;
|
||||
}
|
||||
else if (allowInventorySwap)
|
||||
{
|
||||
return item.ParentInventory is CharacterInventory ?
|
||||
QuickUseAction.TakeFromCharacter : QuickUseAction.TakeFromContainer;
|
||||
if (item.Container == null || character.Inventory.FindIndex(item.Container) == -1) // Not a subinventory in the character's inventory
|
||||
{
|
||||
return item.ParentInventory is CharacterInventory ?
|
||||
QuickUseAction.TakeFromCharacter : QuickUseAction.TakeFromContainer;
|
||||
}
|
||||
else
|
||||
{
|
||||
var selectedContainer = character.SelectedConstruction?.GetComponent<ItemContainer>();
|
||||
if (selectedContainer != null &&
|
||||
selectedContainer.Inventory != null &&
|
||||
!selectedContainer.Inventory.Locked &&
|
||||
allowInventorySwap)
|
||||
{
|
||||
// Move the item from the subinventory to the selected container
|
||||
return QuickUseAction.PutToContainer;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Take from the subinventory and place it in the character's main inventory if no target container is selected
|
||||
return QuickUseAction.TakeFromContainer;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -756,7 +836,23 @@ namespace Barotrauma
|
||||
}
|
||||
break;
|
||||
case QuickUseAction.TakeFromContainer:
|
||||
success = TryPutItemWithAutoEquipCheck(item, Character.Controlled, item.AllowedSlots, true);
|
||||
// Check open subinventories and put the item in it if equipped
|
||||
ItemInventory activeSubInventory = null;
|
||||
for (int i = 0; i < capacity; i++)
|
||||
{
|
||||
activeSubInventory = GetActiveEquippedSubInventory(i);
|
||||
if (activeSubInventory != null)
|
||||
{
|
||||
success = activeSubInventory.TryPutItem(item, Character.Controlled, item.AllowedSlots, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// No subinventory found or placing unsuccessful -> attempt to put in the character's inventory
|
||||
if (!success)
|
||||
{
|
||||
success = TryPutItemWithAutoEquipCheck(item, Character.Controlled, item.AllowedSlots, true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -134,7 +134,7 @@ namespace Barotrauma.Items.Components
|
||||
if (item.Submarine != null) pos += item.Submarine.DrawPosition;
|
||||
pos.Y = -pos.Y;
|
||||
|
||||
if (brokenSprite == null || item.Health > 0.0f)
|
||||
if (brokenSprite == null || !IsBroken)
|
||||
{
|
||||
spriteBatch.Draw(doorSprite.Texture, pos,
|
||||
new Rectangle((int) (doorSprite.SourceRect.X + doorSprite.size.X * openState),
|
||||
@@ -160,7 +160,7 @@ namespace Barotrauma.Items.Components
|
||||
if (item.Submarine != null) pos += item.Submarine.DrawPosition;
|
||||
pos.Y = -pos.Y;
|
||||
|
||||
if (brokenSprite == null || item.Health > 0.0f)
|
||||
if (brokenSprite == null || !IsBroken)
|
||||
{
|
||||
spriteBatch.Draw(doorSprite.Texture, pos,
|
||||
new Rectangle(doorSprite.SourceRect.X,
|
||||
@@ -217,7 +217,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
}
|
||||
|
||||
public override void ClientRead(ServerNetObject type, Lidgren.Network.NetBuffer msg, float sendingTime)
|
||||
public override void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
|
||||
{
|
||||
base.ClientRead(type, msg, sendingTime);
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using Barotrauma.Networking;
|
||||
using Barotrauma.Sounds;
|
||||
using Lidgren.Network;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
@@ -188,7 +187,9 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
if (loopingSound != null)
|
||||
{
|
||||
if (Vector3.DistanceSquared(GameMain.SoundManager.ListenerPosition, new Vector3(position.X, position.Y, 0.0f)) > loopingSound.Range * loopingSound.Range)
|
||||
float targetGain = 0.0f;
|
||||
if (Vector3.DistanceSquared(GameMain.SoundManager.ListenerPosition, new Vector3(position.X, position.Y, 0.0f)) > loopingSound.Range * loopingSound.Range ||
|
||||
(targetGain = GetSoundVolume(loopingSound)) <= 0.0001f)
|
||||
{
|
||||
if (loopingSoundChannel != null)
|
||||
{
|
||||
@@ -220,7 +221,6 @@ namespace Barotrauma.Items.Components
|
||||
lastMuffleCheckTime = (float)Timing.TotalTime;
|
||||
}
|
||||
loopingSoundChannel.Muffled = shouldMuffleLooping;
|
||||
float targetGain = GetSoundVolume(loopingSound);
|
||||
float gainDiff = targetGain - loopingSoundChannel.Gain;
|
||||
loopingSoundChannel.Gain += Math.Abs(gainDiff) < 0.1f ? gainDiff : Math.Sign(gainDiff) * 0.1f;
|
||||
loopingSoundChannel.Position = new Vector3(position.X, position.Y, 0.0f);
|
||||
@@ -258,7 +258,6 @@ namespace Barotrauma.Items.Components
|
||||
itemSound = matchingSounds[index];
|
||||
PlaySound(matchingSounds[index], position, user);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -278,6 +277,8 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
if (loopingSoundChannel == null || !loopingSoundChannel.IsPlaying)
|
||||
{
|
||||
float volume = GetSoundVolume(itemSound);
|
||||
if (volume <= 0.0001f) { return; }
|
||||
loopingSoundChannel = loopingSound.RoundSound.Sound.Play(
|
||||
new Vector3(position.X, position.Y, 0.0f),
|
||||
0.01f,
|
||||
@@ -291,7 +292,7 @@ namespace Barotrauma.Items.Components
|
||||
else
|
||||
{
|
||||
float volume = GetSoundVolume(itemSound);
|
||||
if (volume <= 0.0f) { return; }
|
||||
if (volume <= 0.0001f) { return; }
|
||||
SoundPlayer.PlaySound(itemSound.RoundSound.Sound, position, volume, itemSound.Range, item.CurrentHull);
|
||||
}
|
||||
}
|
||||
@@ -465,14 +466,14 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
|
||||
//Starts a coroutine that will read the correct state of the component from the NetBuffer when correctionTimer reaches zero.
|
||||
protected void StartDelayedCorrection(ServerNetObject type, NetBuffer buffer, float sendingTime, bool waitForMidRoundSync = false)
|
||||
protected void StartDelayedCorrection(ServerNetObject type, IReadMessage buffer, float sendingTime, bool waitForMidRoundSync = false)
|
||||
{
|
||||
if (delayedCorrectionCoroutine != null) CoroutineManager.StopCoroutines(delayedCorrectionCoroutine);
|
||||
|
||||
delayedCorrectionCoroutine = CoroutineManager.StartCoroutine(DoDelayedCorrection(type, buffer, sendingTime, waitForMidRoundSync));
|
||||
}
|
||||
|
||||
private IEnumerable<object> DoDelayedCorrection(ServerNetObject type, NetBuffer buffer, float sendingTime, bool waitForMidRoundSync)
|
||||
private IEnumerable<object> DoDelayedCorrection(ServerNetObject type, IReadMessage buffer, float sendingTime, bool waitForMidRoundSync)
|
||||
{
|
||||
while (GameMain.Client != null &&
|
||||
(correctionTimer > 0.0f || (waitForMidRoundSync && GameMain.Client.MidRoundSyncing)))
|
||||
|
||||
@@ -73,6 +73,11 @@ namespace Barotrauma.Items.Components
|
||||
set;
|
||||
}
|
||||
|
||||
[Serialize(false, false)]
|
||||
public bool KeepOpenWhenEquipped { get; set; }
|
||||
[Serialize(false, false)]
|
||||
public bool MovableFrame { get; set; }
|
||||
|
||||
public Vector2 DrawSize
|
||||
{
|
||||
//use the extents of the item as the draw size
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
using Barotrauma.Networking;
|
||||
using Lidgren.Network;
|
||||
|
||||
namespace Barotrauma.Items.Components
|
||||
{
|
||||
partial class LevelResource : ItemComponent, IServerSerializable
|
||||
{
|
||||
public void ClientRead(ServerNetObject type, NetBuffer msg, float sendingTime)
|
||||
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
|
||||
{
|
||||
deattachTimer = msg.ReadSingle();
|
||||
if (deattachTimer >= DeattachDuration)
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using Barotrauma.Lights;
|
||||
using Barotrauma.Networking;
|
||||
using Lidgren.Network;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
@@ -36,7 +35,7 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
public void ClientRead(ServerNetObject type, NetBuffer msg, float sendingTime)
|
||||
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
|
||||
{
|
||||
IsOn = msg.ReadBoolean();
|
||||
}
|
||||
|
||||
@@ -38,6 +38,8 @@ namespace Barotrauma.Items.Components
|
||||
private void ToggleCrewArea(bool value, bool storeOriginalState)
|
||||
{
|
||||
var crewManager = GameMain.GameSession.CrewManager;
|
||||
if (crewManager == null) { return; }
|
||||
|
||||
if (storeOriginalState)
|
||||
{
|
||||
crewAreaOriginalState = crewManager.ToggleCrewAreaOpen;
|
||||
@@ -48,6 +50,8 @@ namespace Barotrauma.Items.Components
|
||||
private void ToggleChatBox(bool value, bool storeOriginalState)
|
||||
{
|
||||
var crewManager = GameMain.GameSession.CrewManager;
|
||||
if (crewManager == null) { return; }
|
||||
|
||||
if (crewManager.IsSinglePlayer)
|
||||
{
|
||||
if (crewManager.ChatBox != null)
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Barotrauma.Networking;
|
||||
using Lidgren.Network;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System.Linq;
|
||||
@@ -94,12 +93,12 @@ namespace Barotrauma.Items.Components
|
||||
return true;
|
||||
}
|
||||
|
||||
public void ClientWrite(NetBuffer msg, object[] extraData = null)
|
||||
public void ClientWrite(IWriteMessage msg, object[] extraData = null)
|
||||
{
|
||||
msg.Write(pendingState);
|
||||
}
|
||||
|
||||
public void ClientRead(ServerNetObject type, NetBuffer msg, float sendingTime)
|
||||
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
|
||||
{
|
||||
SetActive(msg.ReadBoolean());
|
||||
progressTimer = msg.ReadSingle();
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Barotrauma.Networking;
|
||||
using Lidgren.Network;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
@@ -134,13 +133,13 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
public void ClientWrite(NetBuffer msg, object[] extraData = null)
|
||||
public void ClientWrite(IWriteMessage msg, object[] extraData = null)
|
||||
{
|
||||
//targetForce can only be adjusted at 10% intervals -> no need for more accuracy than this
|
||||
msg.WriteRangedInteger(-10, 10, (int)(targetForce / 10.0f));
|
||||
msg.WriteRangedIntegerDeprecated(-10, 10, (int)(targetForce / 10.0f));
|
||||
}
|
||||
|
||||
public void ClientRead(ServerNetObject type, NetBuffer msg, float sendingTime)
|
||||
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
|
||||
{
|
||||
if (correctionTimer > 0.0f)
|
||||
{
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using Barotrauma.Extensions;
|
||||
using Barotrauma.Networking;
|
||||
using Lidgren.Network;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
@@ -460,13 +459,13 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
public void ClientWrite(NetBuffer msg, object[] extraData = null)
|
||||
public void ClientWrite(IWriteMessage msg, object[] extraData = null)
|
||||
{
|
||||
int itemIndex = pendingFabricatedItem == null ? -1 : fabricationRecipes.IndexOf(pendingFabricatedItem);
|
||||
msg.WriteRangedInteger(-1, fabricationRecipes.Count - 1, itemIndex);
|
||||
msg.WriteRangedIntegerDeprecated(-1, fabricationRecipes.Count - 1, itemIndex);
|
||||
}
|
||||
|
||||
public void ClientRead(ServerNetObject type, NetBuffer msg, float sendingTime)
|
||||
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
|
||||
{
|
||||
int itemIndex = msg.ReadRangedInteger(-1, fabricationRecipes.Count - 1);
|
||||
UInt16 userID = msg.ReadUInt16();
|
||||
@@ -487,4 +486,4 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ namespace Barotrauma.Items.Components
|
||||
private GUIScrollBar isActiveSlider;
|
||||
private GUIScrollBar pumpSpeedSlider;
|
||||
private GUITickBox powerIndicator;
|
||||
private GUITickBox autoControlIndicator;
|
||||
|
||||
private List<Pair<Vector2, ParticleEmitter>> pumpOutEmitters = new List<Pair<Vector2, ParticleEmitter>>();
|
||||
private List<Pair<Vector2, ParticleEmitter>> pumpInEmitters = new List<Pair<Vector2, ParticleEmitter>>();
|
||||
@@ -71,12 +72,20 @@ namespace Barotrauma.Items.Components
|
||||
return true;
|
||||
};
|
||||
|
||||
var rightArea = new GUILayoutGroup(new RectTransform(new Vector2(0.75f, 1.0f), paddedFrame.RectTransform, Anchor.CenterRight)) { RelativeSpacing = 0.1f };
|
||||
var rightArea = new GUILayoutGroup(new RectTransform(new Vector2(0.75f, 0.95f), paddedFrame.RectTransform, Anchor.CenterRight))
|
||||
{
|
||||
RelativeSpacing = 0.1f,
|
||||
Stretch = true
|
||||
};
|
||||
|
||||
powerIndicator = new GUITickBox(new RectTransform(new Point((int)(30 * GUI.Scale)), rightArea.RectTransform), TextManager.Get("PumpPowered"), style: "IndicatorLightGreen")
|
||||
{
|
||||
CanBeFocused = false
|
||||
};
|
||||
autoControlIndicator = new GUITickBox(new RectTransform(new Point((int)(30 * GUI.Scale)), rightArea.RectTransform), TextManager.Get("PumpAutoControl", fallBackTag: "ReactorAutoControl"), style: "IndicatorLightGreen")
|
||||
{
|
||||
CanBeFocused = false
|
||||
};
|
||||
|
||||
var pumpSpeedText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.2f), rightArea.RectTransform) { RelativeOffset = new Vector2(0.0f, 0.0f) },
|
||||
"", textAlignment: Alignment.BottomLeft, wrap: true);
|
||||
@@ -86,12 +95,12 @@ namespace Barotrauma.Items.Components
|
||||
var sliderArea = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.3f), rightArea.RectTransform, Anchor.CenterLeft), isHorizontal: true)
|
||||
{
|
||||
Stretch = true,
|
||||
RelativeSpacing = 0.05f
|
||||
RelativeSpacing = 0.01f
|
||||
};
|
||||
|
||||
var outLabel = new GUITextBlock(new RectTransform(new Vector2(0.3f, 1.0f), sliderArea.RectTransform),
|
||||
TextManager.Get("PumpOut"), textAlignment: Alignment.Center, wrap: true, font: GUI.SmallFont);
|
||||
pumpSpeedSlider = new GUIScrollBar(new RectTransform(new Vector2(0.8f, 1.0f), sliderArea.RectTransform), barSize: 0.25f, style: "GUISlider")
|
||||
var outLabel = new GUITextBlock(new RectTransform(new Vector2(0.25f, 1.0f), sliderArea.RectTransform),
|
||||
TextManager.Get("PumpOut"), textAlignment: Alignment.Center, wrap: false, font: GUI.SmallFont);
|
||||
pumpSpeedSlider = new GUIScrollBar(new RectTransform(new Vector2(0.5f, 1.0f), sliderArea.RectTransform), barSize: 0.25f, style: "GUISlider")
|
||||
{
|
||||
Step = 0.05f,
|
||||
OnMoved = (GUIScrollBar scrollBar, float barScroll) =>
|
||||
@@ -109,9 +118,11 @@ namespace Barotrauma.Items.Components
|
||||
return true;
|
||||
}
|
||||
};
|
||||
var inLabel = new GUITextBlock(new RectTransform(new Vector2(0.3f, 1.0f), sliderArea.RectTransform),
|
||||
TextManager.Get("PumpIn"), textAlignment: Alignment.Center, wrap: true, font: GUI.SmallFont);
|
||||
var inLabel = new GUITextBlock(new RectTransform(new Vector2(0.25f, 1.0f), sliderArea.RectTransform),
|
||||
TextManager.Get("PumpIn"), textAlignment: Alignment.Center, wrap: false, font: GUI.SmallFont);
|
||||
|
||||
rightArea.Recalculate();
|
||||
sliderArea.Recalculate();
|
||||
GUITextBlock.AutoScaleAndNormalize(outLabel, inLabel);
|
||||
}
|
||||
|
||||
@@ -120,7 +131,6 @@ namespace Barotrauma.Items.Components
|
||||
if (pumpSpeedSlider != null)
|
||||
{
|
||||
pumpSpeedSlider.BarScroll = (flowPercentage + 100.0f) / 200.0f;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -151,6 +161,8 @@ namespace Barotrauma.Items.Components
|
||||
public override void UpdateHUD(Character character, float deltaTime, Camera cam)
|
||||
{
|
||||
powerIndicator.Selected = hasPower && IsActive;
|
||||
autoControlIndicator.Selected = controlLockTimer > 0.0f && IsActive;
|
||||
pumpSpeedSlider.Enabled = controlLockTimer <= 0.0f && IsActive;
|
||||
|
||||
if (!PlayerInput.LeftButtonHeld())
|
||||
{
|
||||
@@ -164,14 +176,14 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
public void ClientWrite(Lidgren.Network.NetBuffer msg, object[] extraData = null)
|
||||
public void ClientWrite(IWriteMessage msg, object[] extraData = null)
|
||||
{
|
||||
//flowpercentage can only be adjusted at 10% intervals -> no need for more accuracy than this
|
||||
msg.WriteRangedInteger(-10, 10, (int)(flowPercentage / 10.0f));
|
||||
msg.WriteRangedIntegerDeprecated(-10, 10, (int)(flowPercentage / 10.0f));
|
||||
msg.Write(IsActive);
|
||||
}
|
||||
|
||||
public void ClientRead(ServerNetObject type, Lidgren.Network.NetBuffer msg, float sendingTime)
|
||||
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
|
||||
{
|
||||
if (correctionTimer > 0.0f)
|
||||
{
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Barotrauma.Networking;
|
||||
using Lidgren.Network;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
@@ -612,7 +611,7 @@ namespace Barotrauma.Items.Components
|
||||
tempRangeIndicator.Remove();
|
||||
}
|
||||
|
||||
public void ClientWrite(NetBuffer msg, object[] extraData = null)
|
||||
public void ClientWrite(IWriteMessage msg, object[] extraData = null)
|
||||
{
|
||||
msg.Write(autoTemp);
|
||||
msg.Write(shutDown);
|
||||
@@ -622,7 +621,7 @@ namespace Barotrauma.Items.Components
|
||||
correctionTimer = CorrectionDelay;
|
||||
}
|
||||
|
||||
public void ClientRead(ServerNetObject type, NetBuffer msg, float sendingTime)
|
||||
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
|
||||
{
|
||||
if (correctionTimer > 0.0f)
|
||||
{
|
||||
|
||||
@@ -332,15 +332,18 @@ namespace Barotrauma.Items.Components
|
||||
float dockingDist = Vector2.Distance(steering.ActiveDockingSource.Item.WorldPosition, steering.DockingTarget.Item.WorldPosition);
|
||||
if (prevDockingDist > steering.DockingAssistThreshold && dockingDist <= steering.DockingAssistThreshold)
|
||||
{
|
||||
zoom = Math.Max(zoom, MathHelper.Lerp(MinZoom, MaxZoom, 0.25f));
|
||||
zoomSlider.BarScroll = 0.25f;
|
||||
zoom = Math.Max(zoom, MathHelper.Lerp(MinZoom, MaxZoom, zoomSlider.BarScroll));
|
||||
}
|
||||
else if (prevDockingDist > steering.DockingAssistThreshold * 0.75f && dockingDist <= steering.DockingAssistThreshold * 0.75f)
|
||||
{
|
||||
zoom = Math.Max(zoom, MathHelper.Lerp(MinZoom, MaxZoom, 0.5f));
|
||||
zoomSlider.BarScroll = 0.5f;
|
||||
zoom = Math.Max(zoom, MathHelper.Lerp(MinZoom, MaxZoom, zoomSlider.BarScroll));
|
||||
}
|
||||
else if (prevDockingDist > steering.DockingAssistThreshold * 0.5f && dockingDist <= steering.DockingAssistThreshold * 0.5f)
|
||||
{
|
||||
zoom = Math.Max(zoom, MathHelper.Lerp(MinZoom, MaxZoom, 0.25f));
|
||||
zoomSlider.BarScroll = 0.25f;
|
||||
zoom = Math.Max(zoom, MathHelper.Lerp(MinZoom, MaxZoom, zoomSlider.BarScroll));
|
||||
}
|
||||
prevDockingDist = Math.Min(dockingDist, prevDockingDist);
|
||||
}
|
||||
@@ -1181,7 +1184,7 @@ namespace Barotrauma.Items.Components
|
||||
2, GUI.SmallFont);
|
||||
}
|
||||
|
||||
public void ClientWrite(Lidgren.Network.NetBuffer msg, object[] extraData = null)
|
||||
public void ClientWrite(IWriteMessage msg, object[] extraData = null)
|
||||
{
|
||||
msg.Write(currentMode == Mode.Active);
|
||||
if (currentMode == Mode.Active)
|
||||
@@ -1195,9 +1198,9 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
public void ClientRead(ServerNetObject type, Lidgren.Network.NetBuffer msg, float sendingTime)
|
||||
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
|
||||
{
|
||||
long msgStartPos = msg.Position;
|
||||
int msgStartPos = msg.BitPosition;
|
||||
|
||||
bool isActive = msg.ReadBoolean();
|
||||
float zoomT = 1.0f;
|
||||
@@ -1215,8 +1218,8 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
if (correctionTimer > 0.0f)
|
||||
{
|
||||
int msgLength = (int)(msg.Position - msgStartPos);
|
||||
msg.Position = msgStartPos;
|
||||
int msgLength = (int)(msg.BitPosition - msgStartPos);
|
||||
msg.BitPosition = msgStartPos;
|
||||
StartDelayedCorrection(type, msg.ExtractBits(msgLength), sendingTime);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -301,10 +301,9 @@ namespace Barotrauma.Items.Components
|
||||
dockingContainer = new GUIFrame(new RectTransform(new Vector2(0.3f, 0.25f), GuiFrame.RectTransform, Anchor.BottomLeft)
|
||||
{ MinSize = new Point(150, 0) }, style: null);
|
||||
var paddedDockingContainer = new GUIFrame(new RectTransform(new Vector2(0.9f, 0.9f), dockingContainer.RectTransform, Anchor.Center), style: null);
|
||||
|
||||
//TODO: add new texts for these ("Dock" & "Undock")
|
||||
dockText = TextManager.Get("captain.dock");
|
||||
undockText = TextManager.Get("captain.undock");
|
||||
|
||||
dockText = TextManager.Get("label.navterminaldock", fallBackTag: "captain.dock");
|
||||
undockText = TextManager.Get("label.navterminalundock", fallBackTag: "captain.undock");
|
||||
dockingButton = new GUIButton(new RectTransform(new Vector2(0.5f, 0.5f), paddedDockingContainer.RectTransform, Anchor.Center), dockText, style: "GUIButtonLarge")
|
||||
{
|
||||
OnClicked = (btn, userdata) =>
|
||||
@@ -786,7 +785,7 @@ namespace Barotrauma.Items.Components
|
||||
steeringIndicator?.Remove();
|
||||
}
|
||||
|
||||
public void ClientWrite(Lidgren.Network.NetBuffer msg, object[] extraData = null)
|
||||
public void ClientWrite(IWriteMessage msg, object[] extraData = null)
|
||||
{
|
||||
msg.Write(autoPilot);
|
||||
msg.Write(dockingNetworkMessagePending);
|
||||
@@ -813,9 +812,9 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
public void ClientRead(ServerNetObject type, Lidgren.Network.NetBuffer msg, float sendingTime)
|
||||
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
|
||||
{
|
||||
long msgStartPos = msg.Position;
|
||||
int msgStartPos = msg.BitPosition;
|
||||
|
||||
bool autoPilot = msg.ReadBoolean();
|
||||
Vector2 newSteeringInput = steeringInput;
|
||||
@@ -831,8 +830,8 @@ namespace Barotrauma.Items.Components
|
||||
if (maintainPos)
|
||||
{
|
||||
newPosToMaintain = new Vector2(
|
||||
msg.ReadFloat(),
|
||||
msg.ReadFloat());
|
||||
msg.ReadSingle(),
|
||||
msg.ReadSingle());
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -841,15 +840,15 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
else
|
||||
{
|
||||
newSteeringInput = new Vector2(msg.ReadFloat(), msg.ReadFloat());
|
||||
newTargetVelocity = new Vector2(msg.ReadFloat(), msg.ReadFloat());
|
||||
newSteeringAdjustSpeed = msg.ReadFloat();
|
||||
newSteeringInput = new Vector2(msg.ReadSingle(), msg.ReadSingle());
|
||||
newTargetVelocity = new Vector2(msg.ReadSingle(), msg.ReadSingle());
|
||||
newSteeringAdjustSpeed = msg.ReadSingle();
|
||||
}
|
||||
|
||||
if (correctionTimer > 0.0f)
|
||||
{
|
||||
int msgLength = (int)(msg.Position - msgStartPos);
|
||||
msg.Position = msgStartPos;
|
||||
int msgLength = (int)(msg.BitPosition - msgStartPos);
|
||||
msg.BitPosition = msgStartPos;
|
||||
StartDelayedCorrection(type, msg.ExtractBits(msgLength), sendingTime);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Barotrauma.Networking;
|
||||
using Lidgren.Network;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
@@ -128,12 +127,12 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
}
|
||||
|
||||
public void ClientWrite(NetBuffer msg, object[] extraData)
|
||||
public void ClientWrite(IWriteMessage msg, object[] extraData)
|
||||
{
|
||||
msg.WriteRangedInteger(0, 10, (int)(rechargeSpeed / MaxRechargeSpeed * 10));
|
||||
msg.WriteRangedIntegerDeprecated(0, 10, (int)(rechargeSpeed / MaxRechargeSpeed * 10));
|
||||
}
|
||||
|
||||
public void ClientRead(ServerNetObject type, NetBuffer msg, float sendingTime)
|
||||
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
|
||||
{
|
||||
if (correctionTimer > 0.0f)
|
||||
{
|
||||
|
||||
@@ -117,17 +117,20 @@ namespace Barotrauma.Items.Components
|
||||
float progressBarState = targetItem.ConditionPercentage / 100.0f;
|
||||
if (!MathUtils.NearlyEqual(progressBarState, prevProgressBarState))
|
||||
{
|
||||
Vector2 progressBarPos = targetItem.DrawPosition;
|
||||
var progressBar = user.UpdateHUDProgressBar(
|
||||
targetItem,
|
||||
progressBarPos,
|
||||
progressBarState,
|
||||
Color.Red, Color.Green);
|
||||
if (progressBar != null) { progressBar.Size = new Vector2(60.0f, 20.0f); }
|
||||
var door = targetItem.GetComponent<Door>();
|
||||
if (door == null || door.Stuck <= 0)
|
||||
{
|
||||
Vector2 progressBarPos = targetItem.DrawPosition;
|
||||
var progressBar = user.UpdateHUDProgressBar(
|
||||
targetItem,
|
||||
progressBarPos,
|
||||
progressBarState,
|
||||
Color.Red, Color.Green);
|
||||
if (progressBar != null) { progressBar.Size = new Vector2(60.0f, 20.0f); }
|
||||
}
|
||||
prevProgressBarState = progressBarState;
|
||||
}
|
||||
|
||||
prevProgressBarState = progressBarState;
|
||||
|
||||
Vector2 particlePos = ConvertUnits.ToDisplayUnits(pickedPosition);
|
||||
if (targetItem.Submarine != null) particlePos += targetItem.Submarine.DrawPosition;
|
||||
foreach (var emitter in ParticleEmitterHitItem)
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using Barotrauma.Networking;
|
||||
using Barotrauma.Particles;
|
||||
using Lidgren.Network;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System.Collections.Generic;
|
||||
@@ -15,6 +14,11 @@ namespace Barotrauma.Items.Components
|
||||
get { return repairButton; }
|
||||
}
|
||||
private GUIButton repairButton;
|
||||
public GUIButton SabotageButton
|
||||
{
|
||||
get { return sabotageButton; }
|
||||
}
|
||||
private GUIButton sabotageButton;
|
||||
private GUIProgressBar progressBar;
|
||||
|
||||
private List<ParticleEmitter> particleEmitters = new List<ParticleEmitter>();
|
||||
@@ -22,6 +26,9 @@ namespace Barotrauma.Items.Components
|
||||
private List<Vector2> particleEmitterConditionRanges = new List<Vector2>();
|
||||
|
||||
private string repairButtonText, repairingText;
|
||||
private string sabotageButtonText, sabotagingText;
|
||||
|
||||
private FixActions requestStartFixAction;
|
||||
|
||||
[Serialize("", false)]
|
||||
public string Description
|
||||
@@ -39,7 +46,7 @@ namespace Barotrauma.Items.Components
|
||||
public override bool ShouldDrawHUD(Character character)
|
||||
{
|
||||
if (!HasRequiredItems(character, false) || character.SelectedConstruction != item) return false;
|
||||
return (item.Condition < ShowRepairUIThreshold || (currentFixer == character && !item.IsFullCondition));
|
||||
return item.ConditionPercentage < ShowRepairUIThreshold || character.IsTraitor && item.ConditionPercentage > MinSabotageCondition || (CurrentFixer == character && (!item.IsFullCondition || (character.IsTraitor && item.ConditionPercentage > MinSabotageCondition)));
|
||||
}
|
||||
|
||||
partial void InitProjSpecific(XElement element)
|
||||
@@ -61,24 +68,34 @@ namespace Barotrauma.Items.Components
|
||||
for (int i = 0; i < requiredSkills.Count; i++)
|
||||
{
|
||||
var skillText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.15f), paddedFrame.RectTransform),
|
||||
" - " + TextManager.AddPunctuation(':', TextManager.Get("SkillName." + requiredSkills[i].Identifier), ((int)requiredSkills[i].Level).ToString()),
|
||||
" - " + TextManager.AddPunctuation(':', TextManager.Get("SkillName." + requiredSkills[i].Identifier), ((int) requiredSkills[i].Level).ToString()),
|
||||
font: GUI.SmallFont)
|
||||
{
|
||||
UserData = requiredSkills[i]
|
||||
};
|
||||
}
|
||||
|
||||
progressBar = new GUIProgressBar(new RectTransform(new Vector2(1.0f, 0.15f), paddedFrame.RectTransform),
|
||||
progressBar = new GUIProgressBar(new RectTransform(new Vector2(1.0f, 0.15f), paddedFrame.RectTransform),
|
||||
color: Color.Green, barSize: 0.0f);
|
||||
|
||||
repairButtonText = TextManager.Get("RepairButton");
|
||||
repairingText = TextManager.Get("Repairing");
|
||||
repairButton = new GUIButton(new RectTransform(new Vector2(0.8f, 0.15f), paddedFrame.RectTransform, Anchor.TopCenter),
|
||||
repairButtonText)
|
||||
repairButton = new GUIButton(new RectTransform(new Vector2(0.8f, 0.15f), paddedFrame.RectTransform, Anchor.TopCenter), repairButtonText)
|
||||
{
|
||||
OnClicked = (btn, obj) =>
|
||||
{
|
||||
currentFixer = Character.Controlled;
|
||||
requestStartFixAction = FixActions.Repair;
|
||||
item.CreateClientEvent(this);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
sabotageButtonText = TextManager.Get("SabotageButton");
|
||||
sabotagingText = TextManager.Get("Sabotaging");
|
||||
sabotageButton = new GUIButton(new RectTransform(new Vector2(0.8f, 0.15f), paddedFrame.RectTransform, Anchor.BottomCenter), sabotageButtonText)
|
||||
{
|
||||
OnClicked = (btn, obj) =>
|
||||
{
|
||||
requestStartFixAction = FixActions.Sabotage;
|
||||
item.CreateClientEvent(this);
|
||||
return true;
|
||||
}
|
||||
@@ -101,6 +118,21 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
partial void UpdateProjSpecific(float deltaTime)
|
||||
{
|
||||
if (!GameMain.IsMultiplayer)
|
||||
{
|
||||
switch (requestStartFixAction)
|
||||
{
|
||||
case FixActions.Repair:
|
||||
case FixActions.Sabotage:
|
||||
StartRepairing(Character.Controlled, requestStartFixAction);
|
||||
requestStartFixAction = FixActions.None;
|
||||
break;
|
||||
default:
|
||||
requestStartFixAction = FixActions.None;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < particleEmitters.Count; i++)
|
||||
{
|
||||
if (item.ConditionPercentage >= particleEmitterConditionRanges[i].X && item.ConditionPercentage <= particleEmitterConditionRanges[i].Y)
|
||||
@@ -117,11 +149,17 @@ namespace Barotrauma.Items.Components
|
||||
progressBar.BarSize = item.Condition / item.MaxCondition;
|
||||
progressBar.Color = ToolBox.GradientLerp(progressBar.BarSize, Color.Red, Color.Orange, Color.Green);
|
||||
|
||||
repairButton.Enabled = currentFixer == null;
|
||||
repairButton.Text = currentFixer == null ?
|
||||
repairButton.Enabled = (currentFixerAction == FixActions.None || (CurrentFixer == character && currentFixerAction != FixActions.Repair)) && item.ConditionPercentage <= ShowRepairUIThreshold;
|
||||
repairButton.Text = (currentFixerAction == FixActions.None || CurrentFixer != character || currentFixerAction != FixActions.Repair) ?
|
||||
repairButtonText :
|
||||
repairingText + new string('.', ((int)(Timing.TotalTime * 2.0f) % 3) + 1);
|
||||
|
||||
sabotageButton.Visible = character.IsTraitor;
|
||||
sabotageButton.Enabled = (currentFixerAction == FixActions.None || (CurrentFixer == character && currentFixerAction != FixActions.Sabotage)) && character.IsTraitor && item.ConditionPercentage > MinSabotageCondition;
|
||||
sabotageButton.Text = (currentFixerAction == FixActions.None || CurrentFixer != character || currentFixerAction != FixActions.Sabotage || !character.IsTraitor) ?
|
||||
sabotageButtonText :
|
||||
sabotagingText + new string('.', ((int)(Timing.TotalTime * 2.0f) % 3) + 1);
|
||||
|
||||
System.Diagnostics.Debug.Assert(GuiFrame.GetChild(0) is GUILayoutGroup, "Repair UI hierarchy has changed, could not find skill texts");
|
||||
foreach (GUIComponent c in GuiFrame.GetChild(0).Children)
|
||||
{
|
||||
@@ -139,14 +177,18 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
public void ClientRead(ServerNetObject type, NetBuffer msg, float sendingTime)
|
||||
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
|
||||
{
|
||||
deteriorationTimer = msg.ReadSingle();
|
||||
deteriorateAlwaysResetTimer = msg.ReadSingle();
|
||||
DeteriorateAlways = msg.ReadBoolean();
|
||||
CurrentFixer = msg.ReadBoolean() ? Character.Controlled : null;
|
||||
currentFixerAction = (FixActions)msg.ReadRangedInteger(0, 2);
|
||||
}
|
||||
|
||||
public void ClientWrite(NetBuffer msg, object[] extraData = null)
|
||||
public void ClientWrite(IWriteMessage msg, object[] extraData = null)
|
||||
{
|
||||
//no need to write anything, just letting the server know we started repairing
|
||||
msg.WriteRangedInteger((int)requestStartFixAction, 0, 2);
|
||||
}
|
||||
|
||||
public void Draw(SpriteBatch spriteBatch, bool editing)
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Barotrauma.Networking;
|
||||
using Lidgren.Network;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
@@ -30,7 +29,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
public override bool ShouldDrawHUD(Character character)
|
||||
{
|
||||
return character == Character.Controlled && character == user;
|
||||
return character == Character.Controlled && character == user && character.SelectedConstruction == item;
|
||||
}
|
||||
|
||||
public override void AddToGUIUpdateList()
|
||||
@@ -40,7 +39,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
public override void UpdateHUD(Character character, float deltaTime, Camera cam)
|
||||
{
|
||||
if (character != Character.Controlled || character != user) return;
|
||||
if (character != Character.Controlled || character != user || character.SelectedConstruction != item) { return; }
|
||||
|
||||
if (HighlightedWire != null)
|
||||
{
|
||||
@@ -64,13 +63,13 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
|
||||
|
||||
public void ClientRead(ServerNetObject type, NetBuffer msg, float sendingTime)
|
||||
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
|
||||
{
|
||||
if (GameMain.Client.MidRoundSyncing)
|
||||
{
|
||||
//delay reading the state until midround syncing is done
|
||||
//because some of the wires connected to the panel may not exist yet
|
||||
long msgStartPos = msg.Position;
|
||||
long msgStartPos = msg.BitPosition;
|
||||
foreach (Connection connection in Connections)
|
||||
{
|
||||
for (int i = 0; i < Connection.MaxLinked; i++)
|
||||
@@ -83,8 +82,8 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
msg.ReadUInt16();
|
||||
}
|
||||
int msgLength = (int)(msg.Position - msgStartPos);
|
||||
msg.Position = msgStartPos;
|
||||
int msgLength = (int)(msg.BitPosition - msgStartPos);
|
||||
msg.BitPosition = (int)msgStartPos;
|
||||
StartDelayedCorrection(type, msg.ExtractBits(msgLength), sendingTime, waitForMidRoundSync: true);
|
||||
}
|
||||
else
|
||||
@@ -93,7 +92,7 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
private void ApplyRemoteState(NetBuffer msg)
|
||||
private void ApplyRemoteState(IReadMessage msg)
|
||||
{
|
||||
List<Wire> prevWires = Connections.SelectMany(c => c.Wires.Where(w => w != null)).ToList();
|
||||
List<Wire> newWires = new List<Wire>();
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Barotrauma.Networking;
|
||||
using Lidgren.Network;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -132,7 +131,7 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
public void ClientWrite(NetBuffer msg, object[] extraData = null)
|
||||
public void ClientWrite(IWriteMessage msg, object[] extraData = null)
|
||||
{
|
||||
//extradata contains an array of buttons clicked by the player (or nothing if the player didn't click anything)
|
||||
for (int i = 0; i < customInterfaceElementList.Count; i++)
|
||||
@@ -148,7 +147,7 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
public void ClientRead(ServerNetObject type, NetBuffer msg, float sendingTime)
|
||||
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
|
||||
{
|
||||
for (int i = 0; i < customInterfaceElementList.Count; i++)
|
||||
{
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using Barotrauma.Networking;
|
||||
using Barotrauma.Particles;
|
||||
using Barotrauma.Sounds;
|
||||
using Lidgren.Network;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
@@ -140,6 +139,11 @@ namespace Barotrauma.Items.Components
|
||||
};
|
||||
}
|
||||
|
||||
public override void Move(Vector2 amount)
|
||||
{
|
||||
widgets.Clear();
|
||||
}
|
||||
|
||||
partial void LaunchProjSpecific()
|
||||
{
|
||||
recoilTimer = Math.Max(Reload, 0.1f);
|
||||
@@ -496,7 +500,7 @@ namespace Barotrauma.Items.Components
|
||||
crosshairPointerSprite?.Draw(spriteBatch, crosshairPointerPos, 0, zoom);
|
||||
}
|
||||
|
||||
public void ClientRead(ServerNetObject type, NetBuffer msg, float sendingTime)
|
||||
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
|
||||
{
|
||||
UInt16 projectileID = msg.ReadUInt16();
|
||||
//projectile removed, do nothing
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using Barotrauma.Extensions;
|
||||
using Barotrauma.Items.Components;
|
||||
using Barotrauma.Networking;
|
||||
using Lidgren.Network;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using Microsoft.Xna.Framework.Input;
|
||||
@@ -20,22 +19,22 @@ namespace Barotrauma
|
||||
public bool Disabled;
|
||||
|
||||
public GUIComponent.ComponentState State;
|
||||
|
||||
|
||||
public Vector2 DrawOffset;
|
||||
|
||||
|
||||
public Color Color;
|
||||
|
||||
public Color HighlightColor;
|
||||
public float HighlightScaleUpAmount;
|
||||
private CoroutineHandle highlightCoroutine;
|
||||
public float HighlightTimer;
|
||||
|
||||
|
||||
public Sprite SlotSprite;
|
||||
|
||||
public Keys QuickUseKey;
|
||||
|
||||
public int SubInventoryDir = -1;
|
||||
|
||||
|
||||
public bool IsHighlighted
|
||||
{
|
||||
get
|
||||
@@ -130,13 +129,15 @@ namespace Barotrauma
|
||||
|
||||
protected float prevUIScale = UIScale;
|
||||
protected float prevHUDScale = GUI.Scale;
|
||||
protected Point prevScreenResolution;
|
||||
|
||||
protected static Sprite slotSpriteSmall, slotSpriteHorizontal, slotSpriteVertical, slotSpriteRound;
|
||||
public static Sprite EquipIndicator, EquipIndicatorHighlight;
|
||||
public static Sprite DropIndicator, DropIndicatorHighlight;
|
||||
public static Inventory DraggingInventory;
|
||||
|
||||
public Rectangle BackgroundFrame { get; protected set; }
|
||||
|
||||
|
||||
private ushort[] receivedItemIDs;
|
||||
private CoroutineHandle syncItemsCoroutine;
|
||||
|
||||
@@ -144,6 +145,13 @@ namespace Barotrauma
|
||||
|
||||
private bool isSubInventory;
|
||||
|
||||
private const float movableFrameRectHeight = 40f;
|
||||
private Color movableFrameRectColor = new Color(60, 60, 60);
|
||||
private Rectangle movableFrameRect;
|
||||
private Point savedPosition, originalPos;
|
||||
private bool canMove = false;
|
||||
private bool positionUpdateQueued = false;
|
||||
|
||||
public class SlotReference
|
||||
{
|
||||
public readonly Inventory ParentInventory;
|
||||
@@ -198,12 +206,12 @@ namespace Barotrauma
|
||||
/// If set, the inventory is automatically positioned inside the rect
|
||||
/// </summary>
|
||||
public RectTransform RectTransform;
|
||||
|
||||
|
||||
public static SlotReference SelectedSlot
|
||||
{
|
||||
get { return selectedSlot; }
|
||||
}
|
||||
|
||||
|
||||
public virtual void CreateSlots()
|
||||
{
|
||||
slots = new InventorySlot[capacity];
|
||||
@@ -249,7 +257,7 @@ namespace Barotrauma
|
||||
slotRect.Y = (int)(topLeft.Y + (rectSize.Y + spacing.Y) * ((int)Math.Floor((double)i / slotsPerRow)));
|
||||
slots[i] = new InventorySlot(slotRect);
|
||||
slots[i].InteractRect = new Rectangle(
|
||||
(int)(slots[i].Rect.X - spacing.X / 2 - 1), (int)(slots[i].Rect.Y - spacing.Y / 2 - 1),
|
||||
(int)(slots[i].Rect.X - spacing.X / 2 - 1), (int)(slots[i].Rect.Y - spacing.Y / 2 - 1),
|
||||
(int)(slots[i].Rect.Width + spacing.X + 2), (int)(slots[i].Rect.Height + spacing.Y + 2));
|
||||
|
||||
if (slots[i].Rect.Width > slots[i].Rect.Height)
|
||||
@@ -273,6 +281,22 @@ namespace Barotrauma
|
||||
{
|
||||
}
|
||||
|
||||
public bool Movable()
|
||||
{
|
||||
return movableFrameRect.Size != Point.Zero;
|
||||
}
|
||||
|
||||
public bool IsInventoryHoverAvailable(Character owner, ItemContainer container)
|
||||
{
|
||||
if (container == null && this is ItemInventory)
|
||||
{
|
||||
container = (this as ItemInventory).Container;
|
||||
}
|
||||
|
||||
if (container == null) return false;
|
||||
return owner.SelectedCharacter != null || !container.KeepOpenWhenEquipped || (!(owner is Character)) || !owner.HasEquippedItem(container.Item);
|
||||
}
|
||||
|
||||
protected virtual bool HideSlot(int i)
|
||||
{
|
||||
return slots[i].Disabled || (hideEmptySlot[i] && Items[i] == null);
|
||||
@@ -280,7 +304,7 @@ namespace Barotrauma
|
||||
|
||||
public virtual void Update(float deltaTime, Camera cam, bool subInventory = false)
|
||||
{
|
||||
if (slots == null || isSubInventory != subInventory ||
|
||||
if (slots == null || isSubInventory != subInventory ||
|
||||
(RectTransform != null && RectTransform.Rect != prevRect))
|
||||
{
|
||||
CreateSlots();
|
||||
@@ -341,12 +365,12 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
slot.State = GUIComponent.ComponentState.None;
|
||||
|
||||
if (mouseOn && (draggingItem != null || selectedSlot == null || selectedSlot.Slot == slot))
|
||||
// &&
|
||||
//(highlightedSubInventories.Count == 0 || highlightedSubInventories.Contains(this) || highlightedSubInventorySlot?.Slot == slot || highlightedSubInventory.Owner == item))
|
||||
|
||||
if (mouseOn && (draggingItem != null || selectedSlot == null || selectedSlot.Slot == slot) && DraggingInventory == null)
|
||||
// &&
|
||||
//(highlightedSubInventories.Count == 0 || highlightedSubInventories.Contains(this) || highlightedSubInventorySlot?.Slot == slot || highlightedSubInventory.Owner == item))
|
||||
{
|
||||
slot.State = GUIComponent.ComponentState.Hover;
|
||||
|
||||
@@ -369,7 +393,7 @@ namespace Barotrauma
|
||||
{
|
||||
doubleClickedItem = item;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -384,7 +408,12 @@ namespace Barotrauma
|
||||
return container.Inventory;
|
||||
}
|
||||
|
||||
float openState;
|
||||
protected virtual ItemInventory GetActiveEquippedSubInventory(int slotIndex)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public float OpenState;
|
||||
|
||||
public void UpdateSubInventory(float deltaTime, int slotIndex, Camera cam)
|
||||
{
|
||||
@@ -394,16 +423,45 @@ namespace Barotrauma
|
||||
var container = item.GetComponent<ItemContainer>();
|
||||
if (container == null || !container.DrawInventory) return;
|
||||
|
||||
var subInventory = container.Inventory;
|
||||
var subInventory = container.Inventory;
|
||||
if (subInventory.slots == null) subInventory.CreateSlots();
|
||||
|
||||
canMove = container.MovableFrame && !subInventory.IsInventoryHoverAvailable(Owner as Character, container) && subInventory.originalPos != Point.Zero;
|
||||
|
||||
if (canMove)
|
||||
{
|
||||
if (subInventory.movableFrameRect.Contains(PlayerInput.MousePosition) && PlayerInput.RightButtonClicked())
|
||||
{
|
||||
container.Inventory.savedPosition = container.Inventory.originalPos;
|
||||
}
|
||||
if (subInventory.movableFrameRect.Contains(PlayerInput.MousePosition) || (DraggingInventory != null && DraggingInventory == subInventory))
|
||||
{
|
||||
if (DraggingInventory == null)
|
||||
{
|
||||
if (PlayerInput.LeftButtonDown())
|
||||
{
|
||||
DraggingInventory = subInventory;
|
||||
}
|
||||
}
|
||||
else if (PlayerInput.LeftButtonReleased())
|
||||
{
|
||||
DraggingInventory = null;
|
||||
subInventory.savedPosition = PlayerInput.MousePosition.ToPoint();
|
||||
}
|
||||
else
|
||||
{
|
||||
subInventory.savedPosition = PlayerInput.MousePosition.ToPoint();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int itemCapacity = subInventory.Items.Length;
|
||||
var slot = slots[slotIndex];
|
||||
int dir = slot.SubInventoryDir;
|
||||
if (itemCapacity == 1 && false)
|
||||
{
|
||||
Point slotSize = (slotSpriteRound.size * UIScale).ToPoint();
|
||||
subInventory.slots[0].Rect =
|
||||
subInventory.slots[0].Rect =
|
||||
new Rectangle(slot.Rect.Center.X - slotSize.X / 2, dir > 0 ? slot.Rect.Bottom + 5 : slot.EquipButtonRect.Bottom + 5, slotSize.X, slotSize.Y);
|
||||
|
||||
subInventory.slots[0].InteractRect = subInventory.slots[0].Rect;
|
||||
@@ -425,30 +483,43 @@ namespace Barotrauma
|
||||
|
||||
int width = (int)(subRect.Width * columns + spacing.X * (columns - 1));
|
||||
int startX = slot.Rect.Center.X - (int)(width / 2.0f);
|
||||
|
||||
//prevent the inventory from extending outside the left side of the screen
|
||||
startX = Math.Max(startX, 10);
|
||||
//same for the right side of the screen
|
||||
startX -= Math.Max((startX + width) - GameMain.GraphicsWidth, 0);
|
||||
|
||||
subRect.X = startX;
|
||||
int startY = dir < 0 ?
|
||||
slot.EquipButtonRect.Y - subRect.Height - (int)(35 * UIScale) :
|
||||
slot.EquipButtonRect.Bottom + (int)(10 * UIScale);
|
||||
subRect.Y = startY;
|
||||
|
||||
if (canMove)
|
||||
{
|
||||
startX += subInventory.savedPosition.X - subInventory.originalPos.X;
|
||||
startY += subInventory.savedPosition.Y - subInventory.originalPos.Y;
|
||||
}
|
||||
|
||||
float totalHeight = itemCapacity / columns * (subRect.Height + spacing.Y);
|
||||
subInventory.openState = subInventory.HideTimer >= 0.5f ?
|
||||
Math.Min(subInventory.openState + deltaTime * 5.0f, 1.0f) :
|
||||
Math.Max(subInventory.openState - deltaTime * 3.0f, 0.0f);
|
||||
int padding = (int)(20 * UIScale);
|
||||
|
||||
//prevent the inventory from extending outside the left side of the screen
|
||||
startX = Math.Max(startX, padding);
|
||||
//same for the right side of the screen
|
||||
startX -= Math.Max(startX + width - GameMain.GraphicsWidth + padding, 0);
|
||||
|
||||
//prevent the inventory from extending outside the top of the screen
|
||||
startY = Math.Max(startY, (int)totalHeight - padding / 2);
|
||||
//same for the bottom side of the screen
|
||||
startY -= Math.Max(startY - GameMain.GraphicsHeight + padding * 2 + (canMove ? (int)(movableFrameRectHeight * UIScale) : 0), 0);
|
||||
|
||||
subRect.X = startX;
|
||||
subRect.Y = startY;
|
||||
|
||||
subInventory.OpenState = subInventory.HideTimer >= 0.5f ?
|
||||
Math.Min(subInventory.OpenState + deltaTime * 5.0f, 1.0f) :
|
||||
Math.Max(subInventory.OpenState - deltaTime * 3.0f, 0.0f);
|
||||
|
||||
for (int i = 0; i < itemCapacity; i++)
|
||||
{
|
||||
{
|
||||
subInventory.slots[i].Rect = subRect;
|
||||
subInventory.slots[i].Rect.Location += new Point(0, (int)totalHeight * -dir);
|
||||
|
||||
subInventory.slots[i].DrawOffset = Vector2.SmoothStep( new Vector2(0, -50 * dir), new Vector2(0, totalHeight * dir), subInventory.openState);
|
||||
|
||||
subInventory.slots[i].DrawOffset = Vector2.SmoothStep(new Vector2(0, -50 * dir), new Vector2(0, totalHeight * dir), subInventory.OpenState);
|
||||
|
||||
subInventory.slots[i].InteractRect = new Rectangle(
|
||||
(int)(subInventory.slots[i].Rect.X - spacing.X / 2 - 1), (int)(subInventory.slots[i].Rect.Y - spacing.Y / 2 - 1),
|
||||
(int)(subInventory.slots[i].Rect.Width + spacing.X + 2), (int)(subInventory.slots[i].Rect.Height + spacing.Y + 2));
|
||||
@@ -463,14 +534,19 @@ namespace Barotrauma
|
||||
{
|
||||
subRect.X = (int)(subInventory.slots[i].Rect.Right + spacing.X);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (canMove)
|
||||
{
|
||||
subInventory.movableFrameRect.X = subRect.X - (int)spacing.X;
|
||||
subInventory.movableFrameRect.Y = subRect.Y + (int)(spacing.Y / 2f);
|
||||
}
|
||||
slots[slotIndex].State = GUIComponent.ComponentState.Hover;
|
||||
}
|
||||
subInventory.isSubInventory = true;
|
||||
subInventory.isSubInventory = true;
|
||||
subInventory.Update(deltaTime, cam, true);
|
||||
}
|
||||
|
||||
|
||||
public virtual void Draw(SpriteBatch spriteBatch, bool subInventory = false)
|
||||
{
|
||||
if (slots == null || isSubInventory != subInventory) return;
|
||||
@@ -497,7 +573,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (Character.Controlled == null) return false;
|
||||
|
||||
if (draggingItem != null) return true;
|
||||
if (draggingItem != null || DraggingInventory != null) return true;
|
||||
|
||||
if (Character.Controlled.Inventory != null)
|
||||
{
|
||||
@@ -571,25 +647,32 @@ namespace Barotrauma
|
||||
if (slotIndex < 0 || slotIndex >= Items.Length) return;
|
||||
#endif
|
||||
|
||||
Rectangle prevScissorRect = spriteBatch.GraphicsDevice.ScissorRectangle;
|
||||
spriteBatch.End();
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred, rasterizerState: GameMain.ScissorTestEnable);
|
||||
if (slots[slotIndex].SubInventoryDir > 0)
|
||||
if (!canMove)
|
||||
{
|
||||
spriteBatch.GraphicsDevice.ScissorRectangle = new Rectangle(
|
||||
new Point(0, slots[slotIndex].Rect.Bottom),
|
||||
new Point(GameMain.GraphicsWidth, (int)Math.Max(GameMain.GraphicsHeight - slots[slotIndex].Rect.Bottom, 0)));
|
||||
Rectangle prevScissorRect = spriteBatch.GraphicsDevice.ScissorRectangle;
|
||||
spriteBatch.End();
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred, rasterizerState: GameMain.ScissorTestEnable);
|
||||
if (slots[slotIndex].SubInventoryDir > 0)
|
||||
{
|
||||
spriteBatch.GraphicsDevice.ScissorRectangle = new Rectangle(
|
||||
new Point(0, slots[slotIndex].Rect.Bottom),
|
||||
new Point(GameMain.GraphicsWidth, (int)Math.Max(GameMain.GraphicsHeight - slots[slotIndex].Rect.Bottom, 0)));
|
||||
}
|
||||
else
|
||||
{
|
||||
spriteBatch.GraphicsDevice.ScissorRectangle = new Rectangle(
|
||||
new Point(0, 0),
|
||||
new Point(GameMain.GraphicsWidth, slots[slotIndex].Rect.Y));
|
||||
}
|
||||
container.Inventory.Draw(spriteBatch, true);
|
||||
spriteBatch.End();
|
||||
spriteBatch.GraphicsDevice.ScissorRectangle = prevScissorRect;
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred);
|
||||
}
|
||||
else
|
||||
{
|
||||
spriteBatch.GraphicsDevice.ScissorRectangle = new Rectangle(
|
||||
new Point(0, 0),
|
||||
new Point(GameMain.GraphicsWidth, slots[slotIndex].Rect.Y));
|
||||
container.Inventory.Draw(spriteBatch, true);
|
||||
}
|
||||
container.Inventory.Draw(spriteBatch, true);
|
||||
spriteBatch.End();
|
||||
spriteBatch.GraphicsDevice.ScissorRectangle = prevScissorRect;
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred);
|
||||
|
||||
container.InventoryBottomSprite?.Draw(spriteBatch,
|
||||
new Vector2(slots[slotIndex].Rect.Center.X, slots[slotIndex].Rect.Y) + slots[slotIndex].DrawOffset,
|
||||
@@ -597,10 +680,33 @@ namespace Barotrauma
|
||||
|
||||
container.InventoryTopSprite?.Draw(spriteBatch,
|
||||
new Vector2(
|
||||
slots[slotIndex].Rect.Center.X,
|
||||
slots[slotIndex].Rect.Center.X,
|
||||
container.Inventory.slots[container.Inventory.slots.Length - 1].Rect.Y) + container.Inventory.slots[container.Inventory.slots.Length - 1].DrawOffset,
|
||||
0.0f, UIScale);
|
||||
|
||||
if (container.MovableFrame && !IsInventoryHoverAvailable(Owner as Character, container))
|
||||
{
|
||||
if (positionUpdateQueued) // Wait a frame before updating the positioning of the container after a resolution change to have everything working
|
||||
{
|
||||
container.Inventory.originalPos = container.Inventory.savedPosition = container.Inventory.movableFrameRect.Center;
|
||||
positionUpdateQueued = false;
|
||||
}
|
||||
|
||||
if (container.Inventory.movableFrameRect.Size == Point.Zero || GUI.HasSizeChanged(prevScreenResolution, prevUIScale, prevHUDScale))
|
||||
{
|
||||
// Reset position
|
||||
container.Inventory.savedPosition = container.Inventory.originalPos;
|
||||
|
||||
prevScreenResolution = new Point(GameMain.GraphicsWidth, GameMain.GraphicsHeight);
|
||||
prevUIScale = UIScale;
|
||||
prevHUDScale = GUI.Scale;
|
||||
int height = (int)(movableFrameRectHeight * UIScale);
|
||||
container.Inventory.movableFrameRect = new Rectangle(container.Inventory.BackgroundFrame.X, container.Inventory.BackgroundFrame.Y - height, container.Inventory.BackgroundFrame.Width, height);
|
||||
positionUpdateQueued = true;
|
||||
}
|
||||
|
||||
GUI.DrawRectangle(spriteBatch, container.Inventory.movableFrameRect, movableFrameRectColor, true);
|
||||
}
|
||||
}
|
||||
|
||||
public static void UpdateDragging()
|
||||
@@ -609,13 +715,13 @@ namespace Barotrauma
|
||||
{
|
||||
Character.Controlled.ClearInputs();
|
||||
|
||||
if (CharacterHealth.OpenHealthWindow != null &&
|
||||
if (CharacterHealth.OpenHealthWindow != null &&
|
||||
CharacterHealth.OpenHealthWindow.OnItemDropped(draggingItem, false))
|
||||
{
|
||||
draggingItem = null;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (selectedSlot == null)
|
||||
{
|
||||
if (DraggingItemToWorld &&
|
||||
@@ -672,12 +778,23 @@ namespace Barotrauma
|
||||
selectedSlot = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected static Rectangle GetSubInventoryHoverArea(SlotReference subSlot)
|
||||
{
|
||||
Rectangle hoverArea = subSlot.Slot.Rect;
|
||||
hoverArea.Location += subSlot.Slot.DrawOffset.ToPoint();
|
||||
hoverArea = Rectangle.Union(hoverArea, subSlot.Slot.EquipButtonRect);
|
||||
Rectangle hoverArea;
|
||||
if (!subSlot.Inventory.Movable())
|
||||
{
|
||||
hoverArea = subSlot.Slot.Rect;
|
||||
hoverArea.Location += subSlot.Slot.DrawOffset.ToPoint();
|
||||
hoverArea = Rectangle.Union(hoverArea, subSlot.Slot.EquipButtonRect);
|
||||
}
|
||||
else
|
||||
{
|
||||
hoverArea = subSlot.Inventory.BackgroundFrame;
|
||||
hoverArea.Location += subSlot.Slot.DrawOffset.ToPoint();
|
||||
hoverArea = Rectangle.Union(hoverArea, subSlot.Inventory.movableFrameRect);
|
||||
}
|
||||
|
||||
if (subSlot.Inventory?.slots != null)
|
||||
{
|
||||
foreach (InventorySlot slot in subSlot.Inventory.slots)
|
||||
@@ -697,12 +814,17 @@ namespace Barotrauma
|
||||
hoverArea.Height -= over;
|
||||
}
|
||||
}
|
||||
hoverArea.Inflate(10, 10);
|
||||
|
||||
float inflateAmount = 10 * UIScale;
|
||||
|
||||
hoverArea.Inflate(inflateAmount, inflateAmount);
|
||||
return hoverArea;
|
||||
}
|
||||
|
||||
public static void DrawFront(SpriteBatch spriteBatch)
|
||||
{
|
||||
if (GUI.PauseMenuOpen || GUI.SettingsMenuOpen) return;
|
||||
|
||||
foreach (var slot in highlightedSubInventorySlots)
|
||||
{
|
||||
int slotIndex = Array.IndexOf(slot.ParentInventory.slots, slot.Slot);
|
||||
@@ -710,7 +832,7 @@ namespace Barotrauma
|
||||
{
|
||||
slot.ParentInventory.DrawSubInventory(spriteBatch, slotIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (draggingItem != null)
|
||||
{
|
||||
@@ -727,7 +849,7 @@ namespace Barotrauma
|
||||
if ((GUI.MouseOn == null || mouseOnHealthInterface) && selectedSlot == null)
|
||||
{
|
||||
var shadowSprite = GUI.Style.GetComponentStyle("OuterGlow").Sprites[GUIComponent.ComponentState.None][0];
|
||||
string toolTip = mouseOnHealthInterface ? TextManager.Get("QuickUseAction.UseTreatment") :
|
||||
string toolTip = mouseOnHealthInterface ? TextManager.Get("QuickUseAction.UseTreatment") :
|
||||
Character.Controlled.FocusedItem != null ?
|
||||
TextManager.GetWithVariable("PutItemIn", "[itemname]", Character.Controlled.FocusedItem.Name, true) :
|
||||
TextManager.Get("DropItem");
|
||||
@@ -807,7 +929,7 @@ namespace Barotrauma
|
||||
{
|
||||
Rectangle rect = slot.Rect;
|
||||
rect.Location += slot.DrawOffset.ToPoint();
|
||||
|
||||
|
||||
if (slot.HighlightColor.A > 0)
|
||||
{
|
||||
float inflateAmount = (slot.HighlightColor.A / 255.0f) * slot.HighlightScaleUpAmount * 0.5f;
|
||||
@@ -860,7 +982,7 @@ namespace Barotrauma
|
||||
Rectangle containedIndicatorArea = new Rectangle(rect.X,
|
||||
dir < 0 ? rect.Bottom + HUDLayoutSettings.Padding / 2 : rect.Y - HUDLayoutSettings.Padding / 2 - ContainedIndicatorHeight, rect.Width, ContainedIndicatorHeight);
|
||||
containedIndicatorArea.Inflate(-4, 0);
|
||||
|
||||
|
||||
if (itemContainer.ContainedStateIndicator?.Texture == null)
|
||||
{
|
||||
containedIndicatorArea.Inflate(0, -2);
|
||||
@@ -882,7 +1004,7 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
indicatorSprite.Draw(spriteBatch, containedIndicatorArea.Center.ToVector2(),
|
||||
(inventory != null && inventory.Locked) ? Color.DarkGray * 0.5f : Color.DarkGray * 0.9f,
|
||||
(inventory != null && inventory.Locked) ? Color.DarkGray * 0.5f : Color.DarkGray * 0.9f,
|
||||
origin: indicatorSprite.size / 2,
|
||||
rotate: 0.0f,
|
||||
scale: indicatorScale);
|
||||
@@ -944,19 +1066,19 @@ namespace Barotrauma
|
||||
sprite.Draw(spriteBatch, itemPos, spriteColor, rotation, scale);
|
||||
}
|
||||
|
||||
if (inventory != null &&
|
||||
if (inventory != null &&
|
||||
!inventory.Locked &&
|
||||
Character.Controlled?.Inventory == inventory &&
|
||||
Character.Controlled?.Inventory == inventory &&
|
||||
slot.QuickUseKey != Keys.None)
|
||||
{
|
||||
GUI.DrawString(spriteBatch, rect.Location.ToVector2(),
|
||||
slot.QuickUseKey.ToString().Substring(1, 1),
|
||||
item == null || !drawItem ? Color.Gray : Color.White,
|
||||
GUI.DrawString(spriteBatch, rect.Location.ToVector2(),
|
||||
slot.QuickUseKey.ToString().Substring(1, 1),
|
||||
item == null || !drawItem ? Color.Gray : Color.White,
|
||||
Color.Black * 0.8f);
|
||||
}
|
||||
}
|
||||
|
||||
public void ClientRead(ServerNetObject type, NetBuffer msg, float sendingTime)
|
||||
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
|
||||
{
|
||||
receivedItemIDs = new ushort[capacity];
|
||||
|
||||
@@ -1036,7 +1158,7 @@ namespace Barotrauma
|
||||
receivedItemIDs = null;
|
||||
}
|
||||
|
||||
public void ClientWrite(NetBuffer msg, object[] extraData = null)
|
||||
public void ClientWrite(IWriteMessage msg, object[] extraData = null)
|
||||
{
|
||||
SharedWrite(msg, extraData);
|
||||
syncItemsDelay = 1.0f;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using Barotrauma.Items.Components;
|
||||
using Barotrauma.Networking;
|
||||
using FarseerPhysics;
|
||||
using Lidgren.Network;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using Microsoft.Xna.Framework.Input;
|
||||
@@ -432,23 +431,6 @@ namespace Barotrauma
|
||||
if (!animate) { continue; }
|
||||
spriteState.OffsetState += deltaTime;
|
||||
spriteState.RotationState += deltaTime;
|
||||
|
||||
bool ConditionalMatches(PropertyConditional conditional)
|
||||
{
|
||||
if (string.IsNullOrEmpty(conditional.TargetItemComponentName))
|
||||
{
|
||||
if (!conditional.Matches(this)) { return false; }
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (ItemComponent component in components)
|
||||
{
|
||||
if (component.Name != conditional.TargetItemComponentName) { continue; }
|
||||
if (!conditional.Matches(component)) { return false; }
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -656,10 +638,11 @@ namespace Barotrauma
|
||||
List<Rectangle> disallowedAreas = new List<Rectangle>();
|
||||
if (GameMain.GameSession?.CrewManager != null && Screen.Selected == GameMain.GameScreen)
|
||||
{
|
||||
int disallowedPadding = (int)(50 * GUI.Scale);
|
||||
disallowedAreas.Add(GameMain.GameSession.CrewManager.GetCharacterListArea());
|
||||
disallowedAreas.Add(new Rectangle(
|
||||
HUDLayoutSettings.ChatBoxArea.X - 50, HUDLayoutSettings.ChatBoxArea.Y,
|
||||
HUDLayoutSettings.ChatBoxArea.Width + 50, HUDLayoutSettings.ChatBoxArea.Height));
|
||||
HUDLayoutSettings.ChatBoxArea.X - disallowedPadding, HUDLayoutSettings.ChatBoxArea.Y,
|
||||
HUDLayoutSettings.ChatBoxArea.Width + disallowedPadding, HUDLayoutSettings.ChatBoxArea.Height));
|
||||
}
|
||||
|
||||
GUI.PreventElementOverlap(elementsToMove, disallowedAreas,
|
||||
@@ -798,7 +781,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (ic is Repairable repairable)
|
||||
{
|
||||
if (Condition < repairable.ShowRepairUIThreshold)
|
||||
if (ConditionPercentage < repairable.ShowRepairUIThreshold)
|
||||
{
|
||||
color = Color.Cyan;
|
||||
}
|
||||
@@ -858,7 +841,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public void ClientRead(ServerNetObject type, NetBuffer msg, float sendingTime)
|
||||
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
|
||||
{
|
||||
if (type == ServerNetObject.ENTITY_POSITION)
|
||||
{
|
||||
@@ -868,7 +851,7 @@ namespace Barotrauma
|
||||
|
||||
NetEntityEvent.Type eventType =
|
||||
(NetEntityEvent.Type)msg.ReadRangedInteger(0, Enum.GetValues(typeof(NetEntityEvent.Type)).Length - 1);
|
||||
|
||||
|
||||
switch (eventType)
|
||||
{
|
||||
case NetEntityEvent.Type.ComponentState:
|
||||
@@ -939,7 +922,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public void ClientWrite(NetBuffer msg, object[] extraData = null)
|
||||
public void ClientWrite(IWriteMessage msg, object[] extraData = null)
|
||||
{
|
||||
if (extraData == null || extraData.Length == 0 || !(extraData[0] is NetEntityEvent.Type))
|
||||
{
|
||||
@@ -947,17 +930,17 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
NetEntityEvent.Type eventType = (NetEntityEvent.Type)extraData[0];
|
||||
msg.WriteRangedInteger(0, Enum.GetValues(typeof(NetEntityEvent.Type)).Length - 1, (int)eventType);
|
||||
msg.WriteRangedIntegerDeprecated(0, Enum.GetValues(typeof(NetEntityEvent.Type)).Length - 1, (int)eventType);
|
||||
switch (eventType)
|
||||
{
|
||||
case NetEntityEvent.Type.ComponentState:
|
||||
int componentIndex = (int)extraData[1];
|
||||
msg.WriteRangedInteger(0, components.Count - 1, componentIndex);
|
||||
msg.WriteRangedIntegerDeprecated(0, components.Count - 1, componentIndex);
|
||||
(components[componentIndex] as IClientSerializable).ClientWrite(msg, extraData);
|
||||
break;
|
||||
case NetEntityEvent.Type.InventoryState:
|
||||
int containerIndex = (int)extraData[1];
|
||||
msg.WriteRangedInteger(0, components.Count - 1, containerIndex);
|
||||
msg.WriteRangedIntegerDeprecated(0, components.Count - 1, containerIndex);
|
||||
(components[containerIndex] as ItemContainer).Inventory.ClientWrite(msg, extraData);
|
||||
break;
|
||||
case NetEntityEvent.Type.Treatment:
|
||||
@@ -1010,7 +993,7 @@ namespace Barotrauma
|
||||
rect.Y = (int)(displayPos.Y + rect.Height / 2.0f);
|
||||
}
|
||||
|
||||
public void ClientReadPosition(ServerNetObject type, NetBuffer msg, float sendingTime)
|
||||
public void ClientReadPosition(ServerNetObject type, IReadMessage msg, float sendingTime)
|
||||
{
|
||||
if (body == null)
|
||||
{
|
||||
@@ -1078,7 +1061,7 @@ namespace Barotrauma
|
||||
GameMain.Client.CreateEntityEvent(this, new object[] { NetEntityEvent.Type.ComponentState, index });
|
||||
}
|
||||
|
||||
public static Item ReadSpawnData(NetBuffer msg, bool spawn = true)
|
||||
public static Item ReadSpawnData(IReadMessage msg, bool spawn = true)
|
||||
{
|
||||
string itemName = msg.ReadString();
|
||||
string itemIdentifier = msg.ReadString();
|
||||
@@ -1140,23 +1123,32 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
Inventory inventory = null;
|
||||
|
||||
var inventoryOwner = FindEntityByID(inventoryId);
|
||||
if (inventoryOwner != null)
|
||||
if (inventoryId > 0)
|
||||
{
|
||||
if (inventoryOwner is Character)
|
||||
var inventoryOwner = FindEntityByID(inventoryId);
|
||||
if (inventoryOwner is Character character)
|
||||
{
|
||||
inventory = (inventoryOwner as Character).Inventory;
|
||||
inventory = character.Inventory;
|
||||
}
|
||||
else if (inventoryOwner is Item)
|
||||
else if (inventoryOwner is Item parentItem)
|
||||
{
|
||||
if ((inventoryOwner as Item).components[itemContainerIndex] is ItemContainer container)
|
||||
if (itemContainerIndex < 0 || itemContainerIndex >= parentItem.components.Count)
|
||||
{
|
||||
string errorMsg = "Failed to spawn item \"" + (itemIdentifier ?? "null") +
|
||||
"\" in the inventory of \"" + parentItem.prefab.Identifier + "\" (component index out of range). Index: " + itemContainerIndex + ", components: " + parentItem.components.Count + ".";
|
||||
GameAnalyticsManager.AddErrorEventOnce("Item.ReadSpawnData:ContainerIndexOutOfRange" + (itemName ?? "null") + (itemIdentifier ?? "null"),
|
||||
GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
|
||||
errorMsg);
|
||||
DebugConsole.ThrowError(errorMsg);
|
||||
}
|
||||
else if (parentItem.components[itemContainerIndex] is ItemContainer container)
|
||||
{
|
||||
inventory = container.Inventory;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var item = new Item(itemPrefab, pos, sub)
|
||||
{
|
||||
ID = itemId
|
||||
@@ -1197,4 +1189,4 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using Barotrauma.Networking;
|
||||
using Barotrauma.Particles;
|
||||
using Barotrauma.Sounds;
|
||||
using Lidgren.Network;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using Microsoft.Xna.Framework.Input;
|
||||
@@ -528,14 +527,14 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public void ClientWrite(NetBuffer msg, object[] extraData = null)
|
||||
public void ClientWrite(IWriteMessage msg, object[] extraData = null)
|
||||
{
|
||||
msg.WriteRangedSingle(MathHelper.Clamp(waterVolume / Volume, 0.0f, 1.5f), 0.0f, 1.5f, 8);
|
||||
|
||||
msg.Write(FireSources.Count > 0);
|
||||
if (FireSources.Count > 0)
|
||||
{
|
||||
msg.WriteRangedInteger(0, 16, Math.Min(FireSources.Count, 16));
|
||||
msg.WriteRangedIntegerDeprecated(0, 16, Math.Min(FireSources.Count, 16));
|
||||
for (int i = 0; i < Math.Min(FireSources.Count, 16); i++)
|
||||
{
|
||||
var fireSource = FireSources[i];
|
||||
@@ -550,7 +549,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public void ClientRead(ServerNetObject type, NetBuffer message, float sendingTime)
|
||||
public void ClientRead(ServerNetObject type, IReadMessage message, float sendingTime)
|
||||
{
|
||||
remoteWaterVolume = message.ReadRangedSingle(0.0f, 1.5f, 8) * Volume;
|
||||
remoteOxygenPercentage = message.ReadRangedSingle(0.0f, 100.0f, 8);
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Barotrauma.Networking;
|
||||
using Lidgren.Network;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using FarseerPhysics.Dynamics;
|
||||
@@ -95,7 +94,7 @@ namespace Barotrauma
|
||||
renderer.DrawBackground(spriteBatch, cam, levelObjectManager, backgroundCreatureManager);
|
||||
}
|
||||
|
||||
public void ClientRead(ServerNetObject type, NetBuffer msg, float sendingTime)
|
||||
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
|
||||
{
|
||||
foreach (LevelWall levelWall in extraWalls)
|
||||
{
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
using Barotrauma.Lights;
|
||||
using Barotrauma.Particles;
|
||||
using Barotrauma.Sounds;
|
||||
using Barotrauma.Networking;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Xml.Linq;
|
||||
using Barotrauma.SpriteDeformations;
|
||||
using Lidgren.Network;
|
||||
using System.Linq;
|
||||
using FarseerPhysics.Dynamics;
|
||||
|
||||
@@ -267,7 +267,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public void ClientRead(NetBuffer msg)
|
||||
public void ClientRead(IReadMessage msg)
|
||||
{
|
||||
for (int i = 0; i < Triggers.Count; i++)
|
||||
{
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Barotrauma.Networking;
|
||||
using Lidgren.Network;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
@@ -165,7 +164,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public void ClientRead(ServerNetObject type, NetBuffer msg, float sendingTime)
|
||||
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
|
||||
{
|
||||
int objIndex = msg.ReadRangedInteger(0, objects.Count);
|
||||
objects[objIndex].ClientRead(msg);
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
using Lidgren.Network;
|
||||
using Barotrauma.Networking;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
partial class LevelTrigger
|
||||
{
|
||||
public void ClientRead(NetBuffer msg)
|
||||
public void ClientRead(IReadMessage msg)
|
||||
{
|
||||
if (ForceFluctuationStrength > 0.0f)
|
||||
{
|
||||
|
||||
@@ -382,7 +382,7 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
selectedList = newSelection;
|
||||
selectedList = new List<MapEntity>(newSelection);
|
||||
//selectedList.Clear();
|
||||
//newSelection.ForEach(e => AddSelection(e));
|
||||
foreach (var entity in newSelection)
|
||||
|
||||
@@ -4,7 +4,6 @@ using Barotrauma.Networking;
|
||||
using FarseerPhysics;
|
||||
using FarseerPhysics.Dynamics;
|
||||
using FarseerPhysics.Dynamics.Contacts;
|
||||
using Lidgren.Network;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
@@ -346,12 +345,23 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public void ClientRead(ServerNetObject type, NetBuffer msg, float sendingTime)
|
||||
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
|
||||
{
|
||||
for (int i = 0; i < Sections.Length; i++)
|
||||
byte sectionCount = msg.ReadByte();
|
||||
if (sectionCount != Sections.Length)
|
||||
{
|
||||
string errorMsg = $"Error while reading a network event for the structure \"{Name}\". Section count does not match (server: {sectionCount} client: {Sections.Length})";
|
||||
DebugConsole.NewMessage(errorMsg, Color.Red);
|
||||
GameAnalyticsManager.AddErrorEventOnce("Structure.ClientRead:SectionCountMismatch", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
||||
}
|
||||
|
||||
for (int i = 0; i < sectionCount; i++)
|
||||
{
|
||||
float damage = msg.ReadRangedSingle(0.0f, 1.0f, 8) * Health;
|
||||
SetDamage(i, damage);
|
||||
if (i < Sections.Length)
|
||||
{
|
||||
SetDamage(i, damage);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
using Barotrauma.RuinGeneration;
|
||||
using Barotrauma.Sounds;
|
||||
using FarseerPhysics;
|
||||
using Lidgren.Network;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
@@ -514,7 +513,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public void ClientRead(ServerNetObject type, NetBuffer msg, float sendingTime)
|
||||
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
|
||||
{
|
||||
var posInfo = PhysicsBody.ClientRead(type, msg, sendingTime, parentDebugName: Name);
|
||||
msg.ReadPadBits();
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using Lidgren.Network;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
@@ -17,7 +16,7 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
|
||||
partial class BanList
|
||||
public partial class BanList
|
||||
{
|
||||
private GUIComponent banFrame;
|
||||
|
||||
@@ -129,7 +128,7 @@ namespace Barotrauma.Networking
|
||||
return true;
|
||||
}
|
||||
|
||||
public void ClientAdminRead(NetBuffer incMsg)
|
||||
public void ClientAdminRead(IReadMessage incMsg)
|
||||
{
|
||||
bool hasPermission = incMsg.ReadBoolean();
|
||||
if (!hasPermission)
|
||||
@@ -142,8 +141,8 @@ namespace Barotrauma.Networking
|
||||
incMsg.ReadPadBits();
|
||||
|
||||
bannedPlayers.Clear();
|
||||
Int32 bannedPlayerCount = incMsg.ReadVariableInt32();
|
||||
for (int i = 0; i < bannedPlayerCount; i++)
|
||||
UInt32 bannedPlayerCount = incMsg.ReadVariableUInt32();
|
||||
for (int i = 0; i < (int)bannedPlayerCount; i++)
|
||||
{
|
||||
string name = incMsg.ReadString();
|
||||
UInt16 uniqueIdentifier = incMsg.ReadUInt16();
|
||||
@@ -172,7 +171,7 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
|
||||
public void ClientAdminWrite(NetBuffer outMsg)
|
||||
public void ClientAdminWrite(IWriteMessage outMsg)
|
||||
{
|
||||
outMsg.Write((UInt16)localRemovedBans.Count);
|
||||
foreach (UInt16 uniqueId in localRemovedBans)
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
using Lidgren.Network;
|
||||
using System;
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace Barotrauma.Networking
|
||||
{
|
||||
partial class ChatMessage
|
||||
{
|
||||
public virtual void ClientWrite(NetOutgoingMessage msg)
|
||||
public virtual void ClientWrite(IWriteMessage msg)
|
||||
{
|
||||
msg.Write((byte)ClientNetObject.CHAT_MESSAGE);
|
||||
msg.Write(NetStateID);
|
||||
@@ -14,7 +13,7 @@ namespace Barotrauma.Networking
|
||||
msg.Write(Text);
|
||||
}
|
||||
|
||||
public static void ClientRead(NetIncomingMessage msg)
|
||||
public static void ClientRead(IReadMessage msg)
|
||||
{
|
||||
UInt16 ID = msg.ReadUInt16();
|
||||
ChatMessageType type = (ChatMessageType)msg.ReadByte();
|
||||
@@ -37,7 +36,11 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
|
||||
if (type == ChatMessageType.Order)
|
||||
if (type == ChatMessageType.ServerMessageBox)
|
||||
{
|
||||
txt = TextManager.GetServerMessage(txt);
|
||||
}
|
||||
else if (type == ChatMessageType.Order)
|
||||
{
|
||||
int orderIndex = msg.ReadByte();
|
||||
UInt16 targetCharacterID = msg.ReadUInt16();
|
||||
@@ -63,17 +66,20 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
txt = order.GetChatMessage(targetCharacter?.Name, senderCharacter?.CurrentHull?.DisplayName, givingOrderToSelf: targetCharacter == senderCharacter, orderOption: orderOption);
|
||||
|
||||
if (order.TargetAllCharacters)
|
||||
if (GameMain.Client.GameStarted)
|
||||
{
|
||||
GameMain.GameSession?.CrewManager?.AddOrder(
|
||||
new Order(order.Prefab, targetEntity, (targetEntity as Item)?.Components.FirstOrDefault(ic => ic.GetType() == order.ItemComponentType), orderGiver: senderCharacter),
|
||||
order.Prefab.FadeOutTime);
|
||||
}
|
||||
else if (targetCharacter != null)
|
||||
{
|
||||
targetCharacter.SetOrder(
|
||||
new Order(order.Prefab, targetEntity, (targetEntity as Item)?.Components.FirstOrDefault(ic => ic.GetType() == order.ItemComponentType), orderGiver: senderCharacter),
|
||||
orderOption, senderCharacter);
|
||||
if (order.TargetAllCharacters)
|
||||
{
|
||||
GameMain.GameSession?.CrewManager?.AddOrder(
|
||||
new Order(order.Prefab, targetEntity, (targetEntity as Item)?.Components.FirstOrDefault(ic => ic.GetType() == order.ItemComponentType), orderGiver: senderCharacter),
|
||||
order.Prefab.FadeOutTime);
|
||||
}
|
||||
else if (targetCharacter != null)
|
||||
{
|
||||
targetCharacter.SetOrder(
|
||||
new Order(order.Prefab, targetEntity, (targetEntity as Item)?.Components.FirstOrDefault(ic => ic.GetType() == order.ItemComponentType), orderGiver: senderCharacter),
|
||||
orderOption, senderCharacter);
|
||||
}
|
||||
}
|
||||
|
||||
if (NetIdUtils.IdMoreRecent(ID, LastID))
|
||||
@@ -90,7 +96,12 @@ namespace Barotrauma.Networking
|
||||
switch (type)
|
||||
{
|
||||
case ChatMessageType.MessageBox:
|
||||
new GUIMessageBox("", txt);
|
||||
case ChatMessageType.ServerMessageBox:
|
||||
//only show the message box if the text differs from the text in the currently visible box
|
||||
if ((GUIMessageBox.VisibleBox as GUIMessageBox)?.Text?.Text != txt)
|
||||
{
|
||||
new GUIMessageBox("", txt);
|
||||
}
|
||||
break;
|
||||
case ChatMessageType.Console:
|
||||
DebugConsole.NewMessage(txt, MessageColor[(int)ChatMessageType.Console]);
|
||||
|
||||
@@ -9,6 +9,7 @@ namespace Barotrauma.Networking
|
||||
struct TempClient
|
||||
{
|
||||
public string Name;
|
||||
public UInt64 SteamID;
|
||||
public byte ID;
|
||||
public UInt16 CharacterID;
|
||||
public bool Muted;
|
||||
@@ -76,7 +77,7 @@ namespace Barotrauma.Networking
|
||||
VoipQueue = null; VoipSound = null;
|
||||
if (ID == GameMain.Client.ID) return;
|
||||
VoipQueue = new VoipQueue(ID, false, true);
|
||||
GameMain.Client.VoipClient.RegisterQueue(VoipQueue);
|
||||
GameMain.Client?.VoipClient?.RegisterQueue(VoipQueue);
|
||||
VoipSound = null;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ namespace Barotrauma
|
||||
{
|
||||
partial class EntitySpawner : Entity, IServerSerializable
|
||||
{
|
||||
public void ClientRead(ServerNetObject type, Lidgren.Network.NetBuffer message, float sendingTime)
|
||||
public void ClientRead(ServerNetObject type, IReadMessage message, float sendingTime)
|
||||
{
|
||||
bool remove = message.ReadBoolean();
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Lidgren.Network;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
@@ -25,13 +24,13 @@ namespace Barotrauma.Networking
|
||||
private set;
|
||||
}
|
||||
|
||||
public ulong FileSize
|
||||
public int FileSize
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public ulong Received
|
||||
public int Received
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
@@ -72,15 +71,15 @@ namespace Barotrauma.Networking
|
||||
private set;
|
||||
}
|
||||
|
||||
public NetConnection Connection
|
||||
public NetworkConnection Connection
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public int SequenceChannel;
|
||||
public int ID;
|
||||
|
||||
public FileTransferIn(NetConnection connection, string filePath, FileTransferType fileType)
|
||||
public FileTransferIn(NetworkConnection connection, string filePath, FileTransferType fileType)
|
||||
{
|
||||
FilePath = filePath;
|
||||
FileName = Path.GetFileName(FilePath);
|
||||
@@ -105,17 +104,16 @@ namespace Barotrauma.Networking
|
||||
TimeStarted = Environment.TickCount;
|
||||
}
|
||||
|
||||
public void ReadBytes(NetIncomingMessage inc)
|
||||
public void ReadBytes(IReadMessage inc, int bytesToRead)
|
||||
{
|
||||
int bytesToRead = inc.LengthBytes - inc.PositionInBytes;
|
||||
if (Received + (ulong)(bytesToRead) > FileSize)
|
||||
if (Received + bytesToRead > FileSize)
|
||||
{
|
||||
//strip out excess bytes
|
||||
bytesToRead -= (int)((Received + (ulong)bytesToRead) - FileSize);
|
||||
bytesToRead -= Received + bytesToRead - FileSize;
|
||||
}
|
||||
|
||||
byte[] all = inc.ReadBytes(bytesToRead);
|
||||
Received += (ulong)all.Length;
|
||||
Received += all.Length;
|
||||
WriteStream.Write(all, 0, all.Length);
|
||||
|
||||
int passed = Environment.TickCount - TimeStarted;
|
||||
@@ -162,6 +160,7 @@ namespace Barotrauma.Networking
|
||||
public TransferInDelegate OnTransferFailed;
|
||||
|
||||
private List<FileTransferIn> activeTransfers;
|
||||
private List<Pair<int, double>> finishedTransfers;
|
||||
|
||||
private Dictionary<FileTransferType, string> downloadFolders = new Dictionary<FileTransferType, string>()
|
||||
{
|
||||
@@ -177,9 +176,10 @@ namespace Barotrauma.Networking
|
||||
public FileReceiver()
|
||||
{
|
||||
activeTransfers = new List<FileTransferIn>();
|
||||
finishedTransfers = new List<Pair<int, double>>();
|
||||
}
|
||||
|
||||
public void ReadMessage(NetIncomingMessage inc)
|
||||
public void ReadMessage(IReadMessage inc)
|
||||
{
|
||||
System.Diagnostics.Debug.Assert(!activeTransfers.Any(t =>
|
||||
t.Status == FileTransferStatus.Error ||
|
||||
@@ -187,26 +187,38 @@ namespace Barotrauma.Networking
|
||||
t.Status == FileTransferStatus.Finished), "List of active file transfers contains entires that should have been removed");
|
||||
|
||||
byte transferMessageType = inc.ReadByte();
|
||||
|
||||
switch (transferMessageType)
|
||||
{
|
||||
case (byte)FileTransferMessageType.Initiate:
|
||||
{
|
||||
var existingTransfer = activeTransfers.Find(t => t.SequenceChannel == inc.SequenceChannel);
|
||||
if (existingTransfer != null)
|
||||
{
|
||||
GameMain.Client.CancelFileTransfer(inc.SequenceChannel);
|
||||
DebugConsole.ThrowError("File transfer error: file transfer initiated on a sequence channel that's already in use");
|
||||
return;
|
||||
}
|
||||
|
||||
byte transferId = inc.ReadByte();
|
||||
var existingTransfer = activeTransfers.Find(t => t.ID == transferId);
|
||||
finishedTransfers.RemoveAll(t => t.First == transferId);
|
||||
byte fileType = inc.ReadByte();
|
||||
ushort chunkLen = inc.ReadUInt16();
|
||||
ulong fileSize = inc.ReadUInt64();
|
||||
//ushort chunkLen = inc.ReadUInt16();
|
||||
int fileSize = inc.ReadInt32();
|
||||
string fileName = inc.ReadString();
|
||||
|
||||
if (existingTransfer != null)
|
||||
{
|
||||
if (fileType != (byte)existingTransfer.FileType ||
|
||||
fileSize != existingTransfer.FileSize ||
|
||||
fileName != existingTransfer.FileName)
|
||||
{
|
||||
GameMain.Client.CancelFileTransfer(transferId);
|
||||
DebugConsole.ThrowError("File transfer error: file transfer initiated with an ID that's already in use");
|
||||
}
|
||||
else //resend acknowledgement packet
|
||||
{
|
||||
GameMain.Client.UpdateFileTransfer(transferId, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ValidateInitialData(fileType, fileName, fileSize, out string errorMsg))
|
||||
{
|
||||
GameMain.Client.CancelFileTransfer(inc.SequenceChannel);
|
||||
GameMain.Client.CancelFileTransfer(transferId);
|
||||
DebugConsole.ThrowError("File transfer failed (" + errorMsg + ")");
|
||||
return;
|
||||
}
|
||||
@@ -216,7 +228,7 @@ namespace Barotrauma.Networking
|
||||
DebugConsole.Log("Received file transfer initiation message: ");
|
||||
DebugConsole.Log(" File: " + fileName);
|
||||
DebugConsole.Log(" Size: " + fileSize);
|
||||
DebugConsole.Log(" Sequence channel: " + inc.SequenceChannel);
|
||||
DebugConsole.Log(" ID: " + transferId);
|
||||
}
|
||||
|
||||
string downloadFolder = downloadFolders[(FileTransferType)fileType];
|
||||
@@ -233,9 +245,9 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
|
||||
FileTransferIn newTransfer = new FileTransferIn(inc.SenderConnection, Path.Combine(downloadFolder, fileName), (FileTransferType)fileType)
|
||||
FileTransferIn newTransfer = new FileTransferIn(inc.Sender, Path.Combine(downloadFolder, fileName), (FileTransferType)fileType)
|
||||
{
|
||||
SequenceChannel = inc.SequenceChannel,
|
||||
ID = transferId,
|
||||
Status = FileTransferStatus.Receiving,
|
||||
FileSize = fileSize
|
||||
};
|
||||
@@ -257,7 +269,7 @@ namespace Barotrauma.Networking
|
||||
else
|
||||
{
|
||||
DebugConsole.NewMessage("Failed to initiate a file transfer {" + e.Message + "}", Color.Red);
|
||||
GameMain.Client.CancelFileTransfer(inc.SequenceChannel);
|
||||
GameMain.Client.CancelFileTransfer(transferId);
|
||||
newTransfer.Status = FileTransferStatus.Error;
|
||||
OnTransferFailed(newTransfer);
|
||||
return;
|
||||
@@ -265,10 +277,13 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
activeTransfers.Add(newTransfer);
|
||||
|
||||
GameMain.Client.UpdateFileTransfer(transferId, 0); //send acknowledgement packet
|
||||
}
|
||||
break;
|
||||
case (byte)FileTransferMessageType.TransferOnSameMachine:
|
||||
{
|
||||
byte transferId = inc.ReadByte();
|
||||
byte fileType = inc.ReadByte();
|
||||
string filePath = inc.ReadString();
|
||||
|
||||
@@ -276,19 +291,19 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
DebugConsole.Log("Received file transfer message on the same machine: ");
|
||||
DebugConsole.Log(" File: " + filePath);
|
||||
DebugConsole.Log(" Sequence channel: " + inc.SequenceChannel);
|
||||
DebugConsole.Log(" ID: " + transferId);
|
||||
}
|
||||
|
||||
if (!File.Exists(filePath))
|
||||
{
|
||||
DebugConsole.ThrowError("File transfer on the same machine failed, file \"" + filePath + "\" not found.");
|
||||
GameMain.Client.CancelFileTransfer(inc.SequenceChannel);
|
||||
GameMain.Client.CancelFileTransfer(transferId);
|
||||
return;
|
||||
}
|
||||
|
||||
FileTransferIn directTransfer = new FileTransferIn(inc.SenderConnection, filePath, (FileTransferType)fileType)
|
||||
FileTransferIn directTransfer = new FileTransferIn(inc.Sender, filePath, (FileTransferType)fileType)
|
||||
{
|
||||
SequenceChannel = inc.SequenceChannel,
|
||||
ID = transferId,
|
||||
Status = FileTransferStatus.Finished,
|
||||
FileSize = 0
|
||||
};
|
||||
@@ -296,79 +311,104 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
break;
|
||||
case (byte)FileTransferMessageType.Data:
|
||||
var activeTransfer = activeTransfers.Find(t => t.Connection == inc.SenderConnection && t.SequenceChannel == inc.SequenceChannel);
|
||||
if (activeTransfer == null)
|
||||
{
|
||||
GameMain.Client.CancelFileTransfer(inc.SequenceChannel);
|
||||
DebugConsole.ThrowError("File transfer error: received data without a transfer initiation message");
|
||||
return;
|
||||
}
|
||||
byte transferId = inc.ReadByte();
|
||||
|
||||
//allow one extra byte at the end for the 0 that identifies non-compressed messages
|
||||
if (activeTransfer.Received + (ulong)(inc.LengthBytes - inc.PositionInBytes) > activeTransfer.FileSize + 1)
|
||||
{
|
||||
GameMain.Client.CancelFileTransfer(inc.SequenceChannel);
|
||||
DebugConsole.ThrowError("File transfer error: Received more data than expected (total received: " + activeTransfer.Received +
|
||||
", msg received: " + (inc.LengthBytes - inc.PositionInBytes) +
|
||||
", msg length: " + inc.LengthBytes +
|
||||
", msg read: " + inc.PositionInBytes +
|
||||
", filesize: " + activeTransfer.FileSize);
|
||||
activeTransfer.Status = FileTransferStatus.Error;
|
||||
StopTransfer(activeTransfer);
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
activeTransfer.ReadBytes(inc);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
GameMain.Client.CancelFileTransfer(inc.SequenceChannel);
|
||||
DebugConsole.ThrowError("File transfer error: " + e.Message);
|
||||
activeTransfer.Status = FileTransferStatus.Error;
|
||||
StopTransfer(activeTransfer, true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (activeTransfer.Status == FileTransferStatus.Finished)
|
||||
{
|
||||
activeTransfer.Dispose();
|
||||
|
||||
if (ValidateReceivedData(activeTransfer, out string errorMessage))
|
||||
var activeTransfer = activeTransfers.Find(t => t.Connection == inc.Sender && t.ID == transferId);
|
||||
if (activeTransfer == null)
|
||||
{
|
||||
StopTransfer(activeTransfer);
|
||||
OnFinished(activeTransfer);
|
||||
//it's possible for the server to send some extra data
|
||||
//before it acknowledges that the download is finished,
|
||||
//so let's suppress the error message in that case
|
||||
finishedTransfers.RemoveAll(t => t.Second + 5.0 < Timing.TotalTime);
|
||||
if (!finishedTransfers.Any(t => t.First == transferId))
|
||||
{
|
||||
GameMain.Client.CancelFileTransfer(transferId);
|
||||
DebugConsole.ThrowError("File transfer error: received data without a transfer initiation message");
|
||||
}
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
new GUIMessageBox("File transfer aborted", errorMessage);
|
||||
|
||||
int offset = inc.ReadInt32();
|
||||
if (offset != activeTransfer.Received)
|
||||
{
|
||||
if (offset < activeTransfer.Received)
|
||||
{
|
||||
GameMain.Client.UpdateFileTransfer(activeTransfer.ID, activeTransfer.Received);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
int bytesToRead = inc.ReadUInt16();
|
||||
|
||||
if (activeTransfer.Received + bytesToRead > activeTransfer.FileSize)
|
||||
{
|
||||
GameMain.Client.CancelFileTransfer(transferId);
|
||||
DebugConsole.ThrowError("File transfer error: Received more data than expected (total received: " + activeTransfer.Received +
|
||||
", msg received: " + (inc.LengthBytes - inc.BytePosition) +
|
||||
", msg length: " + inc.LengthBytes +
|
||||
", msg read: " + inc.BytePosition +
|
||||
", filesize: " + activeTransfer.FileSize);
|
||||
activeTransfer.Status = FileTransferStatus.Error;
|
||||
StopTransfer(activeTransfer);
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
activeTransfer.ReadBytes(inc, bytesToRead);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
GameMain.Client.CancelFileTransfer(transferId);
|
||||
DebugConsole.ThrowError("File transfer error: " + e.Message);
|
||||
activeTransfer.Status = FileTransferStatus.Error;
|
||||
StopTransfer(activeTransfer, true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (activeTransfer.Status == FileTransferStatus.Finished)
|
||||
{
|
||||
GameMain.Client.UpdateFileTransfer(activeTransfer.ID, activeTransfer.Received, true);
|
||||
activeTransfer.Dispose();
|
||||
|
||||
if (ValidateReceivedData(activeTransfer, out string errorMessage))
|
||||
{
|
||||
finishedTransfers.Add(new Pair<int, double>(transferId, Timing.TotalTime));
|
||||
StopTransfer(activeTransfer);
|
||||
OnFinished(activeTransfer);
|
||||
}
|
||||
else
|
||||
{
|
||||
new GUIMessageBox("File transfer aborted", errorMessage);
|
||||
|
||||
activeTransfer.Status = FileTransferStatus.Error;
|
||||
StopTransfer(activeTransfer, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case (byte)FileTransferMessageType.Cancel:
|
||||
byte sequenceChannel = inc.ReadByte();
|
||||
var matchingTransfer = activeTransfers.Find(t => t.Connection == inc.SenderConnection && t.SequenceChannel == sequenceChannel);
|
||||
if (matchingTransfer != null)
|
||||
{
|
||||
new GUIMessageBox("File transfer cancelled", "The server has cancelled the transfer of the file \"" + matchingTransfer.FileName + "\".");
|
||||
StopTransfer(matchingTransfer);
|
||||
byte transferId = inc.ReadByte();
|
||||
var matchingTransfer = activeTransfers.Find(t => t.Connection == inc.Sender && t.ID == transferId);
|
||||
if (matchingTransfer != null)
|
||||
{
|
||||
new GUIMessageBox("File transfer cancelled", "The server has cancelled the transfer of the file \"" + matchingTransfer.FileName + "\".");
|
||||
StopTransfer(matchingTransfer);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private bool ValidateInitialData(byte type, string fileName, ulong fileSize, out string errorMessage)
|
||||
private bool ValidateInitialData(byte type, string fileName, int fileSize, out string errorMessage)
|
||||
{
|
||||
errorMessage = "";
|
||||
|
||||
if (fileSize > MaxFileSize)
|
||||
{
|
||||
errorMessage = "File too large (" + MathUtils.GetBytesReadable((long)fileSize) + ")";
|
||||
errorMessage = "File too large (" + MathUtils.GetBytesReadable(fileSize) + ")";
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,7 @@
|
||||
using System;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Microsoft.Xna.Framework;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
@@ -10,6 +10,10 @@ namespace Barotrauma
|
||||
public void CreateSettingsFrame(GUIComponent parent)
|
||||
{
|
||||
CreateLabeledSlider(parent, 0.0f, 40.0f, 1.0f, "KickBanThreshold");
|
||||
if (TextManager.ContainsTag("Karma.KicksBeforeBan"))
|
||||
{
|
||||
CreateLabeledNumberInput(parent, 0, 10, "KicksBeforeBan");
|
||||
}
|
||||
CreateLabeledSlider(parent, 0.0f, 50.0f, 1.0f, "HerpesThreshold");
|
||||
|
||||
CreateLabeledSlider(parent, 0.0f, 0.5f, 0.01f, "KarmaDecay");
|
||||
@@ -37,7 +41,7 @@ namespace Barotrauma
|
||||
CreateLabeledSlider(parent, 0.0f, 1.0f, 0.01f, "DamageFriendlyKarmaDecrease");
|
||||
CreateLabeledSlider(parent, 0.0f, 100.0f, 1.0f, "ReactorMeltdownKarmaDecrease");
|
||||
CreateLabeledSlider(parent, 0.0f, 10.0f, 0.05f, "ReactorOverheatKarmaDecrease");
|
||||
CreateLabeledSlider(parent, 0.0f, 20.0f, 1f, "AllowedWireDisconnectionsPerMinute");
|
||||
CreateLabeledNumberInput(parent, 0, 20, "AllowedWireDisconnectionsPerMinute");
|
||||
CreateLabeledSlider(parent, 0.0f, 20.0f, 0.5f, "WireDisconnectionKarmaDecrease");
|
||||
CreateLabeledSlider(parent, 0.0f, 30.0f, 1.0f, "SpamFilterKarmaDecrease");
|
||||
}
|
||||
@@ -74,5 +78,29 @@ namespace Barotrauma
|
||||
GameMain.NetworkMember.ServerSettings.AssignGUIComponent(propertyName, slider);
|
||||
slider.OnMoved(slider, slider.BarScroll);
|
||||
}
|
||||
|
||||
private void CreateLabeledNumberInput(GUIComponent parent, int min, int max, string propertyName)
|
||||
{
|
||||
var container = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.1f), parent.RectTransform), isHorizontal: true)
|
||||
{
|
||||
Stretch = true,
|
||||
RelativeSpacing = 0.05f,
|
||||
ToolTip = TextManager.Get("Karma." + propertyName + "ToolTip")
|
||||
};
|
||||
|
||||
string labelText = TextManager.Get("Karma." + propertyName);
|
||||
var label = new GUITextBlock(new RectTransform(new Vector2(0.7f, 0.8f), container.RectTransform),
|
||||
labelText, font: GUI.SmallFont)
|
||||
{
|
||||
ToolTip = TextManager.Get("Karma." + propertyName + "ToolTip")
|
||||
};
|
||||
|
||||
var numInput = new GUINumberInput(new RectTransform(new Vector2(0.3f, 0.8f), container.RectTransform), GUINumberInput.NumberType.Int)
|
||||
{
|
||||
MinValueInt = min,
|
||||
MaxValueFloat = max
|
||||
};
|
||||
GameMain.NetworkMember.ServerSettings.AssignGUIComponent(propertyName, numInput);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Lidgren.Network;
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Barotrauma.Networking
|
||||
@@ -75,7 +74,7 @@ namespace Barotrauma.Networking
|
||||
events.Add(newEvent);
|
||||
}
|
||||
|
||||
public void Write(NetOutgoingMessage msg, NetConnection serverConnection)
|
||||
public void Write(IWriteMessage msg, NetworkConnection serverConnection)
|
||||
{
|
||||
if (events.Count == 0 || serverConnection == null) return;
|
||||
|
||||
@@ -97,7 +96,7 @@ namespace Barotrauma.Networking
|
||||
//find the first event that hasn't been sent in roundtriptime or at all
|
||||
eventLastSent.TryGetValue(events[i].ID, out float lastSent);
|
||||
|
||||
if (lastSent > NetTime.Now - serverConnection.AverageRoundtripTime)
|
||||
if (lastSent > Lidgren.Network.NetTime.Now - 50) //TODO: reimplement serverConnection.AverageRoundtripTime
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -109,7 +108,7 @@ namespace Barotrauma.Networking
|
||||
|
||||
foreach (NetEntityEvent entityEvent in eventsToSync)
|
||||
{
|
||||
eventLastSent[entityEvent.ID] = (float)NetTime.Now;
|
||||
eventLastSent[entityEvent.ID] = (float)Lidgren.Network.NetTime.Now;
|
||||
}
|
||||
|
||||
msg.Write((byte)ClientNetObject.ENTITY_STATE);
|
||||
@@ -121,7 +120,7 @@ namespace Barotrauma.Networking
|
||||
/// <summary>
|
||||
/// Read the events from the message, ignoring ones we've already received. Returns false if reading the events fails.
|
||||
/// </summary>
|
||||
public bool Read(ServerNetObject type, NetIncomingMessage msg, float sendingTime, List<IServerSerializable> entities)
|
||||
public bool Read(ServerNetObject type, IReadMessage msg, float sendingTime, List<IServerSerializable> entities)
|
||||
{
|
||||
UInt16 unreceivedEntityEventCount = 0;
|
||||
|
||||
@@ -176,7 +175,7 @@ namespace Barotrauma.Networking
|
||||
|
||||
IServerSerializable entity = Entity.FindEntityByID(entityID) as IServerSerializable;
|
||||
entities.Add(entity);
|
||||
|
||||
|
||||
//skip the event if we've already received it or if the entity isn't found
|
||||
if (thisEventID != (UInt16)(lastReceivedID + 1) || entity == null)
|
||||
{
|
||||
@@ -200,11 +199,11 @@ namespace Barotrauma.Networking
|
||||
return false;
|
||||
}
|
||||
|
||||
msg.Position += msgLength * 8;
|
||||
msg.BitPosition += msgLength * 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
long msgPosition = msg.Position;
|
||||
long msgPosition = msg.BitPosition;
|
||||
if (GameSettings.VerboseLogging)
|
||||
{
|
||||
DebugConsole.NewMessage("received msg " + thisEventID + " (" + entity.ToString() + ")",
|
||||
@@ -231,7 +230,7 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
GameAnalyticsManager.AddErrorEventOnce("ClientEntityEventManager.Read:ReadFailed" + entity.ToString(),
|
||||
GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
||||
msg.Position = msgPosition + msgLength * 8;
|
||||
msg.BitPosition = (int)(msgPosition + msgLength * 8);
|
||||
}
|
||||
}
|
||||
msg.ReadPadBits();
|
||||
@@ -239,7 +238,7 @@ namespace Barotrauma.Networking
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override void WriteEvent(NetBuffer buffer, NetEntityEvent entityEvent, Client recipient = null)
|
||||
protected override void WriteEvent(IWriteMessage buffer, NetEntityEvent entityEvent, Client recipient = null)
|
||||
{
|
||||
var clientEvent = entityEvent as ClientEntityEvent;
|
||||
if (clientEvent == null) return;
|
||||
@@ -248,7 +247,7 @@ namespace Barotrauma.Networking
|
||||
clientEvent.Sent = true;
|
||||
}
|
||||
|
||||
protected void ReadEvent(NetIncomingMessage buffer, IServerSerializable entity, float sendingTime)
|
||||
protected void ReadEvent(IReadMessage buffer, IServerSerializable entity, float sendingTime)
|
||||
{
|
||||
entity.ClientRead(ServerNetObject.ENTITY_EVENT, buffer, sendingTime);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Lidgren.Network;
|
||||
using System;
|
||||
using System;
|
||||
|
||||
namespace Barotrauma.Networking
|
||||
{
|
||||
@@ -15,7 +14,7 @@ namespace Barotrauma.Networking
|
||||
serializable = entity;
|
||||
}
|
||||
|
||||
public void Write(NetBuffer msg)
|
||||
public void Write(IWriteMessage msg)
|
||||
{
|
||||
msg.Write(CharacterStateID);
|
||||
serializable.ClientWrite(msg, Data);
|
||||
|
||||
@@ -5,7 +5,7 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
partial class OrderChatMessage : ChatMessage
|
||||
{
|
||||
public override void ClientWrite(NetOutgoingMessage msg)
|
||||
public override void ClientWrite(IWriteMessage msg)
|
||||
{
|
||||
msg.Write((byte)ClientNetObject.CHAT_MESSAGE);
|
||||
msg.Write(NetStateID);
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Barotrauma.Networking
|
||||
{
|
||||
abstract class ClientPeer
|
||||
{
|
||||
public delegate void MessageCallback(IReadMessage message);
|
||||
public delegate void DisconnectCallback(string msg);
|
||||
public delegate void PasswordCallback(int salt, int retries);
|
||||
public delegate void InitializationCompleteCallback();
|
||||
|
||||
public MessageCallback OnMessageReceived;
|
||||
public DisconnectCallback OnDisconnect;
|
||||
public PasswordCallback OnRequestPassword;
|
||||
public InitializationCompleteCallback OnInitializationComplete;
|
||||
|
||||
public string Name;
|
||||
|
||||
public string Version { get; protected set; }
|
||||
|
||||
public NetworkConnection ServerConnection { get; protected set; }
|
||||
|
||||
public abstract void Start(object endPoint, int ownerKey);
|
||||
public abstract void Close(string msg = null);
|
||||
public abstract void Update(float deltaTime);
|
||||
public abstract void Send(IWriteMessage msg, DeliveryMethod deliveryMethod);
|
||||
public abstract void SendPassword(string password);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,253 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using Lidgren.Network;
|
||||
using Facepunch.Steamworks;
|
||||
using Barotrauma.Steam;
|
||||
using System.Linq;
|
||||
|
||||
namespace Barotrauma.Networking
|
||||
{
|
||||
class LidgrenClientPeer : ClientPeer
|
||||
{
|
||||
private bool isActive;
|
||||
private NetClient netClient;
|
||||
private NetPeerConfiguration netPeerConfiguration;
|
||||
|
||||
private ConnectionInitialization initializationStep;
|
||||
private int ownerKey;
|
||||
private int passwordSalt;
|
||||
private Auth.Ticket steamAuthTicket;
|
||||
List<NetIncomingMessage> incomingLidgrenMessages;
|
||||
|
||||
public LidgrenClientPeer(string name)
|
||||
{
|
||||
ServerConnection = null;
|
||||
|
||||
Name = name;
|
||||
|
||||
netClient = null;
|
||||
isActive = false;
|
||||
}
|
||||
|
||||
public override void Start(object endPoint, int ownerKey)
|
||||
{
|
||||
if (isActive) { return; }
|
||||
|
||||
this.ownerKey = ownerKey;
|
||||
|
||||
netPeerConfiguration = new NetPeerConfiguration("barotrauma");
|
||||
|
||||
netPeerConfiguration.DisableMessageType(NetIncomingMessageType.DebugMessage | NetIncomingMessageType.WarningMessage | NetIncomingMessageType.Receipt
|
||||
| NetIncomingMessageType.ErrorMessage | NetIncomingMessageType.Error);
|
||||
|
||||
netClient = new NetClient(netPeerConfiguration);
|
||||
|
||||
if (SteamManager.IsInitialized)
|
||||
{
|
||||
steamAuthTicket = SteamManager.GetAuthSessionTicket();
|
||||
//TODO: wait for GetAuthSessionTicketResponse_t
|
||||
|
||||
if (steamAuthTicket == null)
|
||||
{
|
||||
throw new Exception("GetAuthSessionTicket returned null");
|
||||
}
|
||||
}
|
||||
|
||||
incomingLidgrenMessages = new List<NetIncomingMessage>();
|
||||
|
||||
initializationStep = ConnectionInitialization.SteamTicketAndVersion;
|
||||
|
||||
if (!(endPoint is IPEndPoint ipEndPoint))
|
||||
{
|
||||
throw new InvalidCastException("endPoint is not IPEndPoint");
|
||||
}
|
||||
if (ServerConnection != null)
|
||||
{
|
||||
throw new InvalidOperationException("ServerConnection is not null");
|
||||
}
|
||||
|
||||
netClient.Start();
|
||||
ServerConnection = new LidgrenConnection("Server", netClient.Connect(ipEndPoint), 0);
|
||||
ServerConnection.Status = NetworkConnectionStatus.Connected;
|
||||
|
||||
isActive = true;
|
||||
}
|
||||
|
||||
public override void Update(float deltaTime)
|
||||
{
|
||||
if (!isActive) { return; }
|
||||
|
||||
netClient.ReadMessages(incomingLidgrenMessages);
|
||||
|
||||
foreach (NetIncomingMessage inc in incomingLidgrenMessages)
|
||||
{
|
||||
if (inc.SenderConnection != (ServerConnection as LidgrenConnection).NetConnection) { continue; }
|
||||
|
||||
switch (inc.MessageType)
|
||||
{
|
||||
case NetIncomingMessageType.Data:
|
||||
HandleDataMessage(inc);
|
||||
break;
|
||||
case NetIncomingMessageType.StatusChanged:
|
||||
HandleStatusChanged(inc);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
incomingLidgrenMessages.Clear();
|
||||
}
|
||||
|
||||
private void HandleDataMessage(NetIncomingMessage inc)
|
||||
{
|
||||
if (!isActive) { return; }
|
||||
|
||||
byte incByte = inc.ReadByte();
|
||||
bool isCompressed = (incByte & (byte)PacketHeader.IsCompressed) != 0;
|
||||
bool isConnectionInitializationStep = (incByte & (byte)PacketHeader.IsConnectionInitializationStep) != 0;
|
||||
|
||||
//DebugConsole.NewMessage(isCompressed + " " + isConnectionInitializationStep + " " + (int)incByte);
|
||||
|
||||
if (isConnectionInitializationStep && initializationStep != ConnectionInitialization.Success)
|
||||
{
|
||||
ReadConnectionInitializationStep(inc);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (initializationStep != ConnectionInitialization.Success)
|
||||
{
|
||||
OnInitializationComplete?.Invoke();
|
||||
initializationStep = ConnectionInitialization.Success;
|
||||
}
|
||||
UInt16 length = inc.ReadUInt16();
|
||||
IReadMessage msg = new ReadOnlyMessage(inc.Data, isCompressed, inc.PositionInBytes, length, ServerConnection);
|
||||
OnMessageReceived?.Invoke(msg);
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleStatusChanged(NetIncomingMessage inc)
|
||||
{
|
||||
if (!isActive) { return; }
|
||||
|
||||
NetConnectionStatus status = (NetConnectionStatus)inc.ReadByte();
|
||||
switch (status)
|
||||
{
|
||||
case NetConnectionStatus.Disconnected:
|
||||
string disconnectMsg = inc.ReadString();
|
||||
Close(disconnectMsg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void ReadConnectionInitializationStep(NetIncomingMessage inc)
|
||||
{
|
||||
if (!isActive) { return; }
|
||||
|
||||
ConnectionInitialization step = (ConnectionInitialization)inc.ReadByte();
|
||||
//DebugConsole.NewMessage(step + " " + initializationStep);
|
||||
switch (step)
|
||||
{
|
||||
case ConnectionInitialization.SteamTicketAndVersion:
|
||||
if (initializationStep != ConnectionInitialization.SteamTicketAndVersion) { return; }
|
||||
NetOutgoingMessage outMsg = netClient.CreateMessage();
|
||||
outMsg.Write((byte)PacketHeader.IsConnectionInitializationStep);
|
||||
outMsg.Write((byte)ConnectionInitialization.SteamTicketAndVersion);
|
||||
outMsg.Write(Name);
|
||||
outMsg.Write(ownerKey);
|
||||
outMsg.Write(SteamManager.GetSteamID());
|
||||
if (steamAuthTicket == null)
|
||||
{
|
||||
outMsg.Write((UInt16)0);
|
||||
}
|
||||
else
|
||||
{
|
||||
outMsg.Write((UInt16)steamAuthTicket.Data.Length);
|
||||
outMsg.Write(steamAuthTicket.Data, 0, steamAuthTicket.Data.Length);
|
||||
}
|
||||
|
||||
outMsg.Write(GameMain.Version.ToString());
|
||||
|
||||
IEnumerable<ContentPackage> mpContentPackages = GameMain.SelectedPackages.Where(cp => cp.HasMultiplayerIncompatibleContent);
|
||||
outMsg.WriteVariableInt32(mpContentPackages.Count());
|
||||
foreach (ContentPackage contentPackage in mpContentPackages)
|
||||
{
|
||||
outMsg.Write(contentPackage.Name);
|
||||
outMsg.Write(contentPackage.MD5hash.Hash);
|
||||
}
|
||||
|
||||
netClient.SendMessage(outMsg, NetDeliveryMethod.ReliableUnordered);
|
||||
break;
|
||||
case ConnectionInitialization.Password:
|
||||
if (initializationStep == ConnectionInitialization.SteamTicketAndVersion) { initializationStep = ConnectionInitialization.Password; }
|
||||
if (initializationStep != ConnectionInitialization.Password) { return; }
|
||||
bool incomingSalt = inc.ReadBoolean(); inc.ReadPadBits();
|
||||
int retries = 0;
|
||||
if (incomingSalt)
|
||||
{
|
||||
passwordSalt = inc.ReadInt32();
|
||||
}
|
||||
else
|
||||
{
|
||||
retries = inc.ReadInt32();
|
||||
}
|
||||
OnRequestPassword?.Invoke(passwordSalt, retries);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public override void SendPassword(string password)
|
||||
{
|
||||
if (!isActive) { return; }
|
||||
|
||||
if (initializationStep != ConnectionInitialization.Password) { return; }
|
||||
NetOutgoingMessage outMsg = netClient.CreateMessage();
|
||||
outMsg.Write((byte)PacketHeader.IsConnectionInitializationStep);
|
||||
outMsg.Write((byte)ConnectionInitialization.Password);
|
||||
byte[] saltedPw = ServerSettings.SaltPassword(NetUtility.ComputeSHAHash(Encoding.UTF8.GetBytes(password)), passwordSalt);
|
||||
outMsg.Write((byte)saltedPw.Length);
|
||||
outMsg.Write(saltedPw, 0, saltedPw.Length);
|
||||
netClient.SendMessage(outMsg, NetDeliveryMethod.ReliableUnordered);
|
||||
}
|
||||
|
||||
public override void Close(string msg = null)
|
||||
{
|
||||
if (!isActive) { return; }
|
||||
|
||||
isActive = false;
|
||||
|
||||
netClient.Shutdown(msg ?? TextManager.Get("Disconnecting"));
|
||||
netClient = null;
|
||||
steamAuthTicket?.Cancel(); steamAuthTicket = null;
|
||||
OnDisconnect?.Invoke(msg);
|
||||
}
|
||||
|
||||
public override void Send(IWriteMessage msg, DeliveryMethod deliveryMethod)
|
||||
{
|
||||
if (!isActive) { 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;
|
||||
}
|
||||
|
||||
NetOutgoingMessage lidgrenMsg = netClient.CreateMessage();
|
||||
byte[] msgData = new byte[msg.LengthBytes];
|
||||
msg.PrepareForSending(ref msgData, out bool isCompressed, out int length);
|
||||
lidgrenMsg.Write((byte)(isCompressed ? PacketHeader.IsCompressed : PacketHeader.None));
|
||||
lidgrenMsg.Write((UInt16)length);
|
||||
lidgrenMsg.Write(msgData, 0, length);
|
||||
|
||||
netClient.SendMessage(lidgrenMsg, lidgrenDeliveryMethod);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,338 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Linq;
|
||||
using Barotrauma.Steam;
|
||||
using Facepunch.Steamworks;
|
||||
using System.Threading;
|
||||
|
||||
namespace Barotrauma.Networking
|
||||
{
|
||||
class SteamP2PClientPeer : ClientPeer
|
||||
{
|
||||
private bool isActive;
|
||||
private UInt64 hostSteamId;
|
||||
private ConnectionInitialization initializationStep;
|
||||
private int passwordSalt;
|
||||
private Auth.Ticket steamAuthTicket;
|
||||
private double timeout;
|
||||
private double heartbeatTimer;
|
||||
|
||||
private List<IReadMessage> incomingInitializationMessages;
|
||||
private List<IReadMessage> incomingDataMessages;
|
||||
|
||||
public SteamP2PClientPeer(string name)
|
||||
{
|
||||
ServerConnection = null;
|
||||
|
||||
Name = name;
|
||||
|
||||
isActive = false;
|
||||
}
|
||||
|
||||
public override void Start(object endPoint, int ownerKey)
|
||||
{
|
||||
steamAuthTicket = SteamManager.GetAuthSessionTicket();
|
||||
//TODO: wait for GetAuthSessionTicketResponse_t
|
||||
|
||||
if (steamAuthTicket == null)
|
||||
{
|
||||
throw new Exception("GetAuthSessionTicket returned null");
|
||||
}
|
||||
|
||||
if (!(endPoint is UInt64 steamIdEndpoint))
|
||||
{
|
||||
throw new InvalidCastException("endPoint is not UInt64");
|
||||
}
|
||||
|
||||
hostSteamId = steamIdEndpoint;
|
||||
|
||||
Steam.SteamManager.Instance.Networking.OnIncomingConnection = OnIncomingConnection;
|
||||
Steam.SteamManager.Instance.Networking.OnP2PData = OnP2PData;
|
||||
Steam.SteamManager.Instance.Networking.SetListenChannel(0, true);
|
||||
|
||||
ServerConnection = new SteamP2PConnection("Server", hostSteamId);
|
||||
|
||||
incomingInitializationMessages = new List<IReadMessage>();
|
||||
incomingDataMessages = new List<IReadMessage>();
|
||||
|
||||
IWriteMessage outMsg = new WriteOnlyMessage();
|
||||
outMsg.Write((byte)DeliveryMethod.Reliable);
|
||||
outMsg.Write((byte)PacketHeader.IsConnectionInitializationStep);
|
||||
outMsg.Write((byte)ConnectionInitialization.ConnectionStarted);
|
||||
|
||||
SteamManager.Instance.Networking.SendP2PPacket(hostSteamId, outMsg.Buffer, outMsg.LengthBytes,
|
||||
Facepunch.Steamworks.Networking.SendType.Reliable);
|
||||
|
||||
initializationStep = ConnectionInitialization.SteamTicketAndVersion;
|
||||
|
||||
timeout = 20.0;
|
||||
heartbeatTimer = 1.0;
|
||||
|
||||
isActive = true;
|
||||
}
|
||||
|
||||
private bool OnIncomingConnection(UInt64 steamId)
|
||||
{
|
||||
if (!isActive) { return false; }
|
||||
return steamId == hostSteamId;
|
||||
}
|
||||
|
||||
private void OnP2PData(ulong steamId, byte[] data, int dataLength, int channel)
|
||||
{
|
||||
if (!isActive) { return; }
|
||||
if (steamId != hostSteamId) { return; }
|
||||
|
||||
timeout = 20.0;
|
||||
|
||||
byte incByte = data[0];
|
||||
bool isCompressed = (incByte & (byte)PacketHeader.IsCompressed) != 0;
|
||||
bool isConnectionInitializationStep = (incByte & (byte)PacketHeader.IsConnectionInitializationStep) != 0;
|
||||
bool isDisconnectMessage = (incByte & (byte)PacketHeader.IsDisconnectMessage) != 0;
|
||||
bool isServerMessage = (incByte & (byte)PacketHeader.IsServerMessage) != 0;
|
||||
bool isHeartbeatMessage = (incByte & (byte)PacketHeader.IsHeartbeatMessage) != 0;
|
||||
|
||||
if (!isServerMessage) { return; }
|
||||
|
||||
if (isConnectionInitializationStep)
|
||||
{
|
||||
ulong low = Lidgren.Network.NetBitWriter.ReadUInt32(data, 32, 8);
|
||||
ulong high = Lidgren.Network.NetBitWriter.ReadUInt32(data, 32, 8+32);
|
||||
ulong lobbyId = low + (high << 32);
|
||||
|
||||
Steam.SteamManager.JoinLobby(lobbyId, false);
|
||||
IReadMessage inc = new ReadOnlyMessage(data, false, 1+8, dataLength - 9, ServerConnection);
|
||||
if (initializationStep != ConnectionInitialization.Success)
|
||||
{
|
||||
incomingInitializationMessages.Add(inc);
|
||||
}
|
||||
}
|
||||
else if (isHeartbeatMessage)
|
||||
{
|
||||
return; //TODO: implement heartbeats
|
||||
}
|
||||
else if (isDisconnectMessage)
|
||||
{
|
||||
IReadMessage inc = new ReadOnlyMessage(data, false, 1, dataLength - 1, ServerConnection);
|
||||
string msg = inc.ReadString();
|
||||
Close(msg);
|
||||
}
|
||||
else
|
||||
{
|
||||
UInt16 length = data[1];
|
||||
length |= (UInt16)(((UInt32)data[2]) << 8);
|
||||
|
||||
IReadMessage inc = new ReadOnlyMessage(data, isCompressed, 3, length, ServerConnection);
|
||||
incomingDataMessages.Add(inc);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Update(float deltaTime)
|
||||
{
|
||||
if (!isActive) { return; }
|
||||
|
||||
timeout -= deltaTime;
|
||||
heartbeatTimer -= deltaTime;
|
||||
|
||||
if (heartbeatTimer < 0.0)
|
||||
{
|
||||
IWriteMessage outMsg = new WriteOnlyMessage();
|
||||
outMsg.Write((byte)DeliveryMethod.Unreliable);
|
||||
outMsg.Write((byte)PacketHeader.IsHeartbeatMessage);
|
||||
|
||||
SteamManager.Instance.Networking.SendP2PPacket(hostSteamId, outMsg.Buffer, outMsg.LengthBytes,
|
||||
Facepunch.Steamworks.Networking.SendType.Unreliable);
|
||||
|
||||
heartbeatTimer = 5.0;
|
||||
}
|
||||
|
||||
if (timeout < 0.0)
|
||||
{
|
||||
Close("Timed out");
|
||||
return;
|
||||
}
|
||||
|
||||
if (initializationStep != ConnectionInitialization.Success)
|
||||
{
|
||||
if (incomingDataMessages.Count > 0)
|
||||
{
|
||||
OnInitializationComplete?.Invoke();
|
||||
initializationStep = ConnectionInitialization.Success;
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (IReadMessage inc in incomingInitializationMessages)
|
||||
{
|
||||
ReadConnectionInitializationStep(inc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (initializationStep == ConnectionInitialization.Success)
|
||||
{
|
||||
foreach (IReadMessage inc in incomingDataMessages)
|
||||
{
|
||||
OnMessageReceived?.Invoke(inc);
|
||||
}
|
||||
}
|
||||
|
||||
incomingInitializationMessages.Clear();
|
||||
incomingDataMessages.Clear();
|
||||
}
|
||||
|
||||
private void ReadConnectionInitializationStep(IReadMessage inc)
|
||||
{
|
||||
if (!isActive) { return; }
|
||||
|
||||
ConnectionInitialization step = (ConnectionInitialization)inc.ReadByte();
|
||||
//DebugConsole.NewMessage(step + " " + initializationStep);
|
||||
switch (step)
|
||||
{
|
||||
case ConnectionInitialization.SteamTicketAndVersion:
|
||||
if (initializationStep != ConnectionInitialization.SteamTicketAndVersion) { return; }
|
||||
IWriteMessage outMsg = new WriteOnlyMessage();
|
||||
outMsg.Write((byte)DeliveryMethod.Reliable);
|
||||
outMsg.Write((byte)PacketHeader.IsConnectionInitializationStep);
|
||||
outMsg.Write((byte)ConnectionInitialization.SteamTicketAndVersion);
|
||||
outMsg.Write(Name);
|
||||
outMsg.Write(SteamManager.GetSteamID());
|
||||
outMsg.Write((UInt16)steamAuthTicket.Data.Length);
|
||||
outMsg.Write(steamAuthTicket.Data, 0, steamAuthTicket.Data.Length);
|
||||
|
||||
outMsg.Write(GameMain.Version.ToString());
|
||||
|
||||
IEnumerable<ContentPackage> mpContentPackages = GameMain.SelectedPackages.Where(cp => cp.HasMultiplayerIncompatibleContent);
|
||||
outMsg.WriteVariableUInt32((UInt32)mpContentPackages.Count());
|
||||
foreach (ContentPackage contentPackage in mpContentPackages)
|
||||
{
|
||||
outMsg.Write(contentPackage.Name);
|
||||
outMsg.Write(contentPackage.MD5hash.Hash);
|
||||
}
|
||||
|
||||
heartbeatTimer = 5.0;
|
||||
SteamManager.Instance.Networking.SendP2PPacket(hostSteamId, outMsg.Buffer, outMsg.LengthBytes,
|
||||
Facepunch.Steamworks.Networking.SendType.Reliable);
|
||||
break;
|
||||
case ConnectionInitialization.Password:
|
||||
if (initializationStep == ConnectionInitialization.SteamTicketAndVersion) { initializationStep = ConnectionInitialization.Password; }
|
||||
if (initializationStep != ConnectionInitialization.Password) { return; }
|
||||
bool incomingSalt = inc.ReadBoolean(); inc.ReadPadBits();
|
||||
int retries = 0;
|
||||
if (incomingSalt)
|
||||
{
|
||||
passwordSalt = inc.ReadInt32();
|
||||
}
|
||||
else
|
||||
{
|
||||
retries = inc.ReadInt32();
|
||||
}
|
||||
OnRequestPassword?.Invoke(passwordSalt, retries);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Send(IWriteMessage msg, DeliveryMethod deliveryMethod)
|
||||
{
|
||||
if (!isActive) { return; }
|
||||
|
||||
byte[] buf = new byte[msg.LengthBytes + 4];
|
||||
buf[0] = (byte)deliveryMethod;
|
||||
|
||||
byte[] bufAux = new byte[msg.LengthBytes];
|
||||
bool isCompressed; int length;
|
||||
msg.PrepareForSending(ref bufAux, out isCompressed, out length);
|
||||
|
||||
buf[1] = (byte)(isCompressed ? PacketHeader.IsCompressed : PacketHeader.None);
|
||||
|
||||
buf[2] = (byte)(length & 0xff);
|
||||
buf[3] = (byte)((length >> 8) & 0xff);
|
||||
|
||||
Array.Copy(bufAux, 0, buf, 4, length);
|
||||
|
||||
Facepunch.Steamworks.Networking.SendType sendType;
|
||||
switch (deliveryMethod)
|
||||
{
|
||||
case DeliveryMethod.Reliable:
|
||||
case DeliveryMethod.ReliableOrdered:
|
||||
//the documentation seems to suggest that the Reliable send type
|
||||
//enforces packet order (TODO: verify)
|
||||
sendType = Facepunch.Steamworks.Networking.SendType.Reliable;
|
||||
break;
|
||||
default:
|
||||
sendType = Facepunch.Steamworks.Networking.SendType.Unreliable;
|
||||
break;
|
||||
}
|
||||
|
||||
if (length + 8 >= MsgConstants.MTU)
|
||||
{
|
||||
DebugConsole.Log("WARNING: message length comes close to exceeding MTU, forcing reliable send (" + length.ToString() + " bytes)");
|
||||
sendType = Facepunch.Steamworks.Networking.SendType.Reliable;
|
||||
}
|
||||
|
||||
heartbeatTimer = 5.0;
|
||||
bool successSend = SteamManager.Instance.Networking.SendP2PPacket(hostSteamId, buf, length + 4, sendType);
|
||||
|
||||
if (!successSend)
|
||||
{
|
||||
if (sendType != Facepunch.Steamworks.Networking.SendType.Reliable)
|
||||
{
|
||||
DebugConsole.Log("WARNING: message couldn't be sent unreliably, forcing reliable send (" + length.ToString() + " bytes)");
|
||||
sendType = Facepunch.Steamworks.Networking.SendType.Reliable;
|
||||
successSend = Steam.SteamManager.Instance.Networking.SendP2PPacket(hostSteamId, buf, length + 4, sendType);
|
||||
}
|
||||
if (!successSend)
|
||||
{
|
||||
DebugConsole.ThrowError("Failed to send message to remote peer! (" + length.ToString() + " bytes)");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void SendPassword(string password)
|
||||
{
|
||||
if (!isActive) { return; }
|
||||
|
||||
if (initializationStep != ConnectionInitialization.Password) { return; }
|
||||
IWriteMessage outMsg = new WriteOnlyMessage();
|
||||
outMsg.Write((byte)DeliveryMethod.Reliable);
|
||||
outMsg.Write((byte)PacketHeader.IsConnectionInitializationStep);
|
||||
outMsg.Write((byte)ConnectionInitialization.Password);
|
||||
byte[] saltedPw = ServerSettings.SaltPassword(Lidgren.Network.NetUtility.ComputeSHAHash(Encoding.UTF8.GetBytes(password)), passwordSalt);
|
||||
outMsg.Write((byte)saltedPw.Length);
|
||||
outMsg.Write(saltedPw, 0, saltedPw.Length);
|
||||
|
||||
heartbeatTimer = 5.0;
|
||||
SteamManager.Instance.Networking.SendP2PPacket(hostSteamId, outMsg.Buffer, outMsg.LengthBytes,
|
||||
Facepunch.Steamworks.Networking.SendType.Reliable);
|
||||
}
|
||||
|
||||
public override void Close(string msg = null)
|
||||
{
|
||||
if (!isActive) { return; }
|
||||
|
||||
SteamManager.LeaveLobby();
|
||||
|
||||
isActive = false;
|
||||
|
||||
IWriteMessage outMsg = new WriteOnlyMessage();
|
||||
outMsg.Write((byte)DeliveryMethod.Reliable);
|
||||
outMsg.Write((byte)PacketHeader.IsDisconnectMessage);
|
||||
outMsg.Write(msg ?? "Disconnected");
|
||||
|
||||
SteamManager.Instance.Networking.SendP2PPacket(hostSteamId, outMsg.Buffer, outMsg.LengthBytes,
|
||||
Facepunch.Steamworks.Networking.SendType.Reliable);
|
||||
|
||||
Thread.Sleep(100);
|
||||
|
||||
Steam.SteamManager.Instance.Networking.OnIncomingConnection = null;
|
||||
Steam.SteamManager.Instance.Networking.OnP2PData = null;
|
||||
Steam.SteamManager.Instance.Networking.SetListenChannel(0, false);
|
||||
|
||||
Steam.SteamManager.Instance.Networking.CloseSession(hostSteamId);
|
||||
|
||||
steamAuthTicket?.Cancel(); steamAuthTicket = null;
|
||||
hostSteamId = 0;
|
||||
|
||||
OnDisconnect?.Invoke(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,472 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using Lidgren.Network;
|
||||
using Facepunch.Steamworks;
|
||||
using Barotrauma.Steam;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
|
||||
namespace Barotrauma.Networking
|
||||
{
|
||||
class SteamP2POwnerPeer : ClientPeer
|
||||
{
|
||||
private bool isActive;
|
||||
private NetClient netClient;
|
||||
private NetPeerConfiguration netPeerConfiguration;
|
||||
|
||||
private ConnectionInitialization initializationStep;
|
||||
private UInt64 selfSteamID;
|
||||
List<NetIncomingMessage> incomingLidgrenMessages;
|
||||
|
||||
class RemotePeer
|
||||
{
|
||||
public UInt64 SteamID;
|
||||
public double? DisconnectTime;
|
||||
public bool Authenticating;
|
||||
public bool Authenticated;
|
||||
public List<Pair<NetDeliveryMethod, NetOutgoingMessage>> UnauthedMessages;
|
||||
|
||||
public RemotePeer(UInt64 steamId)
|
||||
{
|
||||
SteamID = steamId;
|
||||
DisconnectTime = null;
|
||||
Authenticating = false;
|
||||
Authenticated = false;
|
||||
|
||||
UnauthedMessages = new List<Pair<NetDeliveryMethod, NetOutgoingMessage>>();
|
||||
}
|
||||
|
||||
}
|
||||
List<RemotePeer> remotePeers;
|
||||
|
||||
public SteamP2POwnerPeer(string name)
|
||||
{
|
||||
ServerConnection = null;
|
||||
|
||||
Name = name;
|
||||
|
||||
netClient = null;
|
||||
isActive = false;
|
||||
|
||||
selfSteamID = Steam.SteamManager.GetSteamID();
|
||||
}
|
||||
|
||||
public override void Start(object endPoint, int ownerKey)
|
||||
{
|
||||
if (isActive) { return; }
|
||||
|
||||
netPeerConfiguration = new NetPeerConfiguration("barotrauma");
|
||||
|
||||
netPeerConfiguration.DisableMessageType(NetIncomingMessageType.DebugMessage | NetIncomingMessageType.WarningMessage | NetIncomingMessageType.Receipt
|
||||
| NetIncomingMessageType.ErrorMessage | NetIncomingMessageType.Error);
|
||||
|
||||
netClient = new NetClient(netPeerConfiguration);
|
||||
|
||||
incomingLidgrenMessages = new List<NetIncomingMessage>();
|
||||
|
||||
initializationStep = ConnectionInitialization.SteamTicketAndVersion;
|
||||
|
||||
IPEndPoint ipEndPoint = new IPEndPoint(IPAddress.Loopback, Steam.SteamManager.STEAMP2P_OWNER_PORT);
|
||||
|
||||
netClient.Start();
|
||||
ServerConnection = new LidgrenConnection("Server", netClient.Connect(ipEndPoint), 0);
|
||||
ServerConnection.Status = NetworkConnectionStatus.Connected;
|
||||
|
||||
remotePeers = new List<RemotePeer>();
|
||||
|
||||
Steam.SteamManager.Instance.Networking.OnIncomingConnection = OnIncomingConnection;
|
||||
Steam.SteamManager.Instance.Networking.OnP2PData = OnP2PData;
|
||||
Steam.SteamManager.Instance.Networking.SetListenChannel(0, true);
|
||||
Steam.SteamManager.Instance.Auth.OnAuthChange = OnAuthChange;
|
||||
|
||||
isActive = true;
|
||||
}
|
||||
|
||||
private void OnAuthChange(ulong steamID, ulong ownerID, ClientAuthStatus status)
|
||||
{
|
||||
RemotePeer remotePeer = remotePeers.Find(p => p.SteamID == steamID);
|
||||
DebugConsole.NewMessage(steamID + " validation: " + status + ", " + (remotePeer != null));
|
||||
|
||||
if (remotePeer == null) { return; }
|
||||
|
||||
if (remotePeer.Authenticated)
|
||||
{
|
||||
if (status != ClientAuthStatus.OK)
|
||||
{
|
||||
DisconnectPeer(remotePeer, DisconnectReason.SteamAuthenticationFailed.ToString() + "/ Steam authentication status changed: " + status.ToString());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (status == ClientAuthStatus.OK)
|
||||
{
|
||||
remotePeer.Authenticated = true;
|
||||
remotePeer.Authenticating = false;
|
||||
foreach (var msg in remotePeer.UnauthedMessages)
|
||||
{
|
||||
netClient.SendMessage(msg.Second, msg.First);
|
||||
}
|
||||
remotePeer.UnauthedMessages.Clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
DisconnectPeer(remotePeer, DisconnectReason.SteamAuthenticationFailed.ToString() + "/ Steam authentication failed: " + status.ToString());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private bool OnIncomingConnection(UInt64 steamId)
|
||||
{
|
||||
if (!isActive) { return false; }
|
||||
|
||||
if (!remotePeers.Any(p => p.SteamID == steamId))
|
||||
{
|
||||
remotePeers.Add(new RemotePeer(steamId));
|
||||
}
|
||||
|
||||
return true; //accept all connections, the server will figure things out later
|
||||
}
|
||||
|
||||
private void OnP2PData(ulong steamId, byte[] data, int dataLength, int channel)
|
||||
{
|
||||
if (!isActive) { return; }
|
||||
|
||||
RemotePeer remotePeer = remotePeers.Find(p => p.SteamID == steamId);
|
||||
if (remotePeer == null || remotePeer.DisconnectTime != null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
NetOutgoingMessage outMsg = netClient.CreateMessage();
|
||||
outMsg.Write(steamId);
|
||||
outMsg.Write(data, 1, dataLength - 1);
|
||||
|
||||
NetDeliveryMethod lidgrenDeliveryMethod = NetDeliveryMethod.Unreliable;
|
||||
switch ((DeliveryMethod)data[0])
|
||||
{
|
||||
case DeliveryMethod.Unreliable:
|
||||
lidgrenDeliveryMethod = NetDeliveryMethod.Unreliable;
|
||||
break;
|
||||
case DeliveryMethod.Reliable:
|
||||
lidgrenDeliveryMethod = NetDeliveryMethod.ReliableUnordered;
|
||||
break;
|
||||
case DeliveryMethod.ReliableOrdered:
|
||||
lidgrenDeliveryMethod = NetDeliveryMethod.ReliableOrdered;
|
||||
break;
|
||||
}
|
||||
|
||||
byte incByte = data[1];
|
||||
bool isCompressed = (incByte & (byte)PacketHeader.IsCompressed) != 0;
|
||||
bool isConnectionInitializationStep = (incByte & (byte)PacketHeader.IsConnectionInitializationStep) != 0;
|
||||
bool isDisconnectMessage = (incByte & (byte)PacketHeader.IsDisconnectMessage) != 0;
|
||||
bool isServerMessage = (incByte & (byte)PacketHeader.IsServerMessage) != 0;
|
||||
bool isHeartbeatMessage = (incByte & (byte)PacketHeader.IsHeartbeatMessage) != 0;
|
||||
|
||||
if (!remotePeer.Authenticated)
|
||||
{
|
||||
if (!remotePeer.Authenticating)
|
||||
{
|
||||
if (isConnectionInitializationStep)
|
||||
{
|
||||
remotePeer.DisconnectTime = null;
|
||||
|
||||
IReadMessage authMsg = new ReadOnlyMessage(data, isCompressed, 2, dataLength - 2, null);
|
||||
ConnectionInitialization initializationStep = (ConnectionInitialization)authMsg.ReadByte();
|
||||
if (initializationStep == ConnectionInitialization.SteamTicketAndVersion)
|
||||
{
|
||||
remotePeer.Authenticating = true;
|
||||
|
||||
authMsg.ReadString(); //skip name
|
||||
authMsg.ReadUInt64(); //skip steamid
|
||||
UInt16 ticketLength = authMsg.ReadUInt16();
|
||||
byte[] ticket = authMsg.ReadBytes(ticketLength);
|
||||
|
||||
ClientStartAuthSessionResult authSessionStartState = Steam.SteamManager.StartAuthSession(ticket, steamId);
|
||||
if (authSessionStartState != ClientStartAuthSessionResult.OK)
|
||||
{
|
||||
DisconnectPeer(remotePeer, DisconnectReason.SteamAuthenticationFailed.ToString() + "/ Steam auth session failed to start: " + authSessionStartState.ToString());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (remotePeer.Authenticating)
|
||||
{
|
||||
remotePeer.UnauthedMessages.Add(new Pair<NetDeliveryMethod, NetOutgoingMessage>(lidgrenDeliveryMethod, outMsg));
|
||||
}
|
||||
else
|
||||
{
|
||||
netClient.SendMessage(outMsg, lidgrenDeliveryMethod);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Update(float deltaTime)
|
||||
{
|
||||
if (!isActive) { return; }
|
||||
|
||||
for (int i = remotePeers.Count - 1; i >= 0; i--)
|
||||
{
|
||||
if (remotePeers[i].DisconnectTime != null && remotePeers[i].DisconnectTime < Timing.TotalTime)
|
||||
{
|
||||
ClosePeerSession(remotePeers[i]);
|
||||
}
|
||||
}
|
||||
|
||||
netClient.ReadMessages(incomingLidgrenMessages);
|
||||
|
||||
foreach (NetIncomingMessage inc in incomingLidgrenMessages)
|
||||
{
|
||||
if (inc.SenderConnection != (ServerConnection as LidgrenConnection).NetConnection) { continue; }
|
||||
|
||||
switch (inc.MessageType)
|
||||
{
|
||||
case NetIncomingMessageType.Data:
|
||||
HandleDataMessage(inc);
|
||||
break;
|
||||
case NetIncomingMessageType.StatusChanged:
|
||||
HandleStatusChanged(inc);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
incomingLidgrenMessages.Clear();
|
||||
}
|
||||
|
||||
private void HandleDataMessage(NetIncomingMessage inc)
|
||||
{
|
||||
if (!isActive) { return; }
|
||||
|
||||
UInt64 recipientSteamId = inc.ReadUInt64();
|
||||
|
||||
int p2pDataStart = inc.PositionInBytes;
|
||||
|
||||
byte incByte = inc.ReadByte();
|
||||
|
||||
bool isCompressed = (incByte & (byte)PacketHeader.IsCompressed) != 0;
|
||||
bool isConnectionInitializationStep = (incByte & (byte)PacketHeader.IsConnectionInitializationStep) != 0;
|
||||
bool isDisconnectMessage = (incByte & (byte)PacketHeader.IsDisconnectMessage) != 0;
|
||||
bool isServerMessage = (incByte & (byte)PacketHeader.IsServerMessage) != 0;
|
||||
bool isHeartbeatMessage = (incByte & (byte)PacketHeader.IsHeartbeatMessage) != 0;
|
||||
|
||||
if (recipientSteamId != selfSteamID)
|
||||
{
|
||||
if (!isServerMessage)
|
||||
{
|
||||
DebugConsole.ThrowError("Received non-server message meant for remote peer");
|
||||
return;
|
||||
}
|
||||
|
||||
RemotePeer peer = remotePeers.Find(p => p.SteamID == recipientSteamId);
|
||||
|
||||
if (peer == null) { return; }
|
||||
|
||||
if (isDisconnectMessage)
|
||||
{
|
||||
DisconnectPeer(peer, inc.ReadString());
|
||||
return;
|
||||
}
|
||||
|
||||
Facepunch.Steamworks.Networking.SendType sendType;
|
||||
switch (inc.DeliveryMethod)
|
||||
{
|
||||
case NetDeliveryMethod.ReliableUnordered:
|
||||
case NetDeliveryMethod.ReliableSequenced:
|
||||
case NetDeliveryMethod.ReliableOrdered:
|
||||
//the documentation seems to suggest that the Reliable send type
|
||||
//enforces packet order (TODO: verify)
|
||||
sendType = Facepunch.Steamworks.Networking.SendType.Reliable;
|
||||
break;
|
||||
default:
|
||||
sendType = Facepunch.Steamworks.Networking.SendType.Unreliable;
|
||||
break;
|
||||
}
|
||||
|
||||
byte[] p2pData;
|
||||
|
||||
if (isConnectionInitializationStep)
|
||||
{
|
||||
p2pData = new byte[inc.LengthBytes - p2pDataStart + 8];
|
||||
p2pData[0] = inc.Data[p2pDataStart];
|
||||
Lidgren.Network.NetBitWriter.WriteUInt64(Steam.SteamManager.Instance.Lobby.CurrentLobby, 64, p2pData, 8);
|
||||
Array.Copy(inc.Data, p2pDataStart+1, p2pData, 9, inc.LengthBytes - p2pDataStart - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
p2pData = new byte[inc.LengthBytes - p2pDataStart];
|
||||
Array.Copy(inc.Data, p2pDataStart, p2pData, 0, p2pData.Length);
|
||||
}
|
||||
|
||||
if (p2pData.Length + 4 >= MsgConstants.MTU)
|
||||
{
|
||||
DebugConsole.Log("WARNING: message length comes close to exceeding MTU, forcing reliable send (" + p2pData.Length.ToString() + " bytes)");
|
||||
sendType = Facepunch.Steamworks.Networking.SendType.Reliable;
|
||||
}
|
||||
|
||||
bool successSend = Steam.SteamManager.Instance.Networking.SendP2PPacket(recipientSteamId, p2pData, p2pData.Length, sendType);
|
||||
|
||||
if (!successSend)
|
||||
{
|
||||
if (sendType != Facepunch.Steamworks.Networking.SendType.Reliable)
|
||||
{
|
||||
DebugConsole.Log("WARNING: message couldn't be sent unreliably, forcing reliable send (" + p2pData.Length.ToString() + " bytes)");
|
||||
sendType = Facepunch.Steamworks.Networking.SendType.Reliable;
|
||||
successSend = Steam.SteamManager.Instance.Networking.SendP2PPacket(recipientSteamId, p2pData, p2pData.Length, sendType);
|
||||
}
|
||||
if (!successSend)
|
||||
{
|
||||
DebugConsole.ThrowError("Failed to send message to remote peer! (" + p2pData.Length.ToString() + " bytes)");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (isDisconnectMessage)
|
||||
{
|
||||
DebugConsole.ThrowError("Received disconnect message from owned server");
|
||||
return;
|
||||
}
|
||||
if (!isServerMessage)
|
||||
{
|
||||
DebugConsole.ThrowError("Received non-server message from owned server");
|
||||
return;
|
||||
}
|
||||
if (isHeartbeatMessage)
|
||||
{
|
||||
return; //timeout is handled by Lidgren, ignore this message
|
||||
}
|
||||
if (isConnectionInitializationStep)
|
||||
{
|
||||
NetOutgoingMessage outMsg = netClient.CreateMessage();
|
||||
outMsg.Write(selfSteamID);
|
||||
outMsg.Write((byte)(PacketHeader.IsConnectionInitializationStep));
|
||||
outMsg.Write(Name);
|
||||
netClient.SendMessage(outMsg, NetDeliveryMethod.ReliableUnordered);
|
||||
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (initializationStep != ConnectionInitialization.Success)
|
||||
{
|
||||
OnInitializationComplete?.Invoke();
|
||||
initializationStep = ConnectionInitialization.Success;
|
||||
}
|
||||
UInt16 length = inc.ReadUInt16();
|
||||
IReadMessage msg = new ReadOnlyMessage(inc.Data, isCompressed, inc.PositionInBytes, length, ServerConnection);
|
||||
OnMessageReceived?.Invoke(msg);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void DisconnectPeer(RemotePeer peer, string msg)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(msg))
|
||||
{
|
||||
if (peer.DisconnectTime == null)
|
||||
{
|
||||
peer.DisconnectTime = Timing.TotalTime + 1.0;
|
||||
}
|
||||
|
||||
IWriteMessage outMsg = new WriteOnlyMessage();
|
||||
outMsg.Write((byte)(PacketHeader.IsServerMessage | PacketHeader.IsDisconnectMessage));
|
||||
outMsg.Write(msg);
|
||||
|
||||
Steam.SteamManager.Instance.Networking.SendP2PPacket(peer.SteamID, outMsg.Buffer, outMsg.LengthBytes,
|
||||
Facepunch.Steamworks.Networking.SendType.Reliable);
|
||||
}
|
||||
else
|
||||
{
|
||||
ClosePeerSession(peer);
|
||||
}
|
||||
}
|
||||
|
||||
private void ClosePeerSession(RemotePeer peer)
|
||||
{
|
||||
Steam.SteamManager.Instance.Networking.CloseSession(peer.SteamID);
|
||||
remotePeers.Remove(peer);
|
||||
}
|
||||
|
||||
private void HandleStatusChanged(NetIncomingMessage inc)
|
||||
{
|
||||
if (!isActive) { return; }
|
||||
|
||||
NetConnectionStatus status = (NetConnectionStatus)inc.ReadByte();
|
||||
switch (status)
|
||||
{
|
||||
case NetConnectionStatus.Disconnected:
|
||||
string disconnectMsg = inc.ReadString();
|
||||
Close(disconnectMsg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public override void SendPassword(string password)
|
||||
{
|
||||
return; //owner doesn't send passwords
|
||||
}
|
||||
|
||||
public override void Close(string msg = null)
|
||||
{
|
||||
if (!isActive) { return; }
|
||||
|
||||
isActive = false;
|
||||
|
||||
for (int i=remotePeers.Count-1;i>=0;i--)
|
||||
{
|
||||
DisconnectPeer(remotePeers[i], msg ?? DisconnectReason.ServerShutdown.ToString());
|
||||
}
|
||||
|
||||
Thread.Sleep(100);
|
||||
|
||||
for (int i = remotePeers.Count - 1; i >= 0; i--)
|
||||
{
|
||||
ClosePeerSession(remotePeers[i]);
|
||||
}
|
||||
|
||||
netClient.Shutdown(msg ?? TextManager.Get("Disconnecting"));
|
||||
netClient = null;
|
||||
|
||||
OnDisconnect?.Invoke(msg);
|
||||
|
||||
Steam.SteamManager.Instance.Networking.OnIncomingConnection = null;
|
||||
Steam.SteamManager.Instance.Networking.OnP2PData = null;
|
||||
Steam.SteamManager.Instance.Networking.SetListenChannel(0, false);
|
||||
Steam.SteamManager.Instance.Auth.OnAuthChange = null;
|
||||
}
|
||||
|
||||
public override void Send(IWriteMessage msg, DeliveryMethod deliveryMethod)
|
||||
{
|
||||
if (!isActive) { 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;
|
||||
}
|
||||
|
||||
NetOutgoingMessage lidgrenMsg = netClient.CreateMessage();
|
||||
byte[] msgData = new byte[msg.LengthBytes];
|
||||
msg.PrepareForSending(ref msgData, out bool isCompressed, out int length);
|
||||
lidgrenMsg.Write(selfSteamID);
|
||||
lidgrenMsg.Write((byte)(isCompressed ? PacketHeader.IsCompressed : PacketHeader.None));
|
||||
lidgrenMsg.Write((UInt16)length);
|
||||
lidgrenMsg.Write(msgData, 0, length);
|
||||
|
||||
netClient.SendMessage(lidgrenMsg, lidgrenDeliveryMethod);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -21,8 +21,7 @@ namespace Barotrauma.Networking
|
||||
GameMain.Client.AddChatMessage("ServerMessage.ShuttleLeaving", ChatMessageType.Server);
|
||||
}
|
||||
}
|
||||
|
||||
public void ClientRead(ServerNetObject type, NetBuffer msg, float sendingTime)
|
||||
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
|
||||
{
|
||||
var newState = (State)msg.ReadRangedInteger(0, Enum.GetNames(typeof(State)).Length);
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Barotrauma.Steam;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
@@ -9,6 +10,9 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
public string IP;
|
||||
public string Port;
|
||||
|
||||
public UInt64 LobbyID;
|
||||
|
||||
public string ServerName;
|
||||
public string ServerMessage;
|
||||
public bool GameStarted;
|
||||
|
||||
@@ -5,7 +5,7 @@ using System.Linq;
|
||||
|
||||
namespace Barotrauma.Networking
|
||||
{
|
||||
partial class ServerLog
|
||||
public partial class ServerLog
|
||||
{
|
||||
public GUIButton LogFrame;
|
||||
private GUIListBox listBox;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Lidgren.Network;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
@@ -31,6 +30,10 @@ namespace Barotrauma.Networking
|
||||
else if (GUIComponent is GUIScrollBar scrollBar) return scrollBar.BarScrollValue;
|
||||
else if (GUIComponent is GUIRadioButtonGroup radioButtonGroup) return radioButtonGroup.Selected;
|
||||
else if (GUIComponent is GUIDropDown dropdown) return dropdown.SelectedData;
|
||||
else if (GUIComponent is GUINumberInput numInput)
|
||||
{
|
||||
if (numInput.InputType == GUINumberInput.NumberType.Int) { return numInput.IntValue; } else { return numInput.FloatValue; }
|
||||
}
|
||||
return null;
|
||||
}
|
||||
set
|
||||
@@ -38,9 +41,30 @@ namespace Barotrauma.Networking
|
||||
if (GUIComponent == null) return;
|
||||
else if (GUIComponent is GUITickBox tickBox) tickBox.Selected = (bool)value;
|
||||
else if (GUIComponent is GUITextBox textBox) textBox.Text = (string)value;
|
||||
else if (GUIComponent is GUIScrollBar scrollBar) scrollBar.BarScrollValue = (float)value;
|
||||
else if (GUIComponent is GUIScrollBar scrollBar)
|
||||
{
|
||||
if (value.GetType() == typeof(int))
|
||||
{
|
||||
scrollBar.BarScrollValue = (int)value;
|
||||
}
|
||||
else
|
||||
{
|
||||
scrollBar.BarScrollValue = (float)value;
|
||||
}
|
||||
}
|
||||
else if (GUIComponent is GUIRadioButtonGroup radioButtonGroup) radioButtonGroup.Selected = (Enum)value;
|
||||
else if (GUIComponent is GUIDropDown dropdown) dropdown.SelectItem(value);
|
||||
else if (GUIComponent is GUINumberInput numInput)
|
||||
{
|
||||
if (numInput.InputType == GUINumberInput.NumberType.Int)
|
||||
{
|
||||
numInput.IntValue = (int)value;
|
||||
}
|
||||
else
|
||||
{
|
||||
numInput.FloatValue = (float)value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,7 +92,7 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
|
||||
public void ClientAdminRead(NetBuffer incMsg)
|
||||
public void ClientAdminRead(IReadMessage incMsg)
|
||||
{
|
||||
int count = incMsg.ReadUInt16();
|
||||
for (int i = 0; i < count; i++)
|
||||
@@ -91,7 +115,7 @@ namespace Barotrauma.Networking
|
||||
else
|
||||
{
|
||||
UInt32 size = incMsg.ReadVariableUInt32();
|
||||
incMsg.Position += 8 * size;
|
||||
incMsg.BitPosition += (int)(8 * size);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,10 +124,14 @@ namespace Barotrauma.Networking
|
||||
Whitelist.ClientAdminRead(incMsg);
|
||||
}
|
||||
|
||||
public void ClientRead(NetBuffer incMsg)
|
||||
public void ClientRead(IReadMessage incMsg)
|
||||
{
|
||||
ServerName = incMsg.ReadString();
|
||||
ServerMessageText = incMsg.ReadString();
|
||||
MaxPlayers = incMsg.ReadByte();
|
||||
HasPassword = incMsg.ReadBoolean();
|
||||
isPublic = incMsg.ReadBoolean();
|
||||
incMsg.ReadPadBits();
|
||||
TickRate = incMsg.ReadRangedInteger(1, 60);
|
||||
GameMain.NetworkMember.TickRate = TickRate;
|
||||
|
||||
@@ -123,7 +151,7 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
if (!GameMain.Client.HasPermission(Networking.ClientPermissions.ManageSettings)) return;
|
||||
|
||||
NetOutgoingMessage outMsg = GameMain.NetworkMember.NetPeer.CreateMessage();
|
||||
IWriteMessage outMsg = new WriteOnlyMessage();
|
||||
|
||||
outMsg.Write((byte)ClientPacketHeader.SERVER_SETTINGS);
|
||||
|
||||
@@ -191,7 +219,7 @@ namespace Barotrauma.Networking
|
||||
outMsg.Write(GameMain.NetLobbyScreen.SeedBox.Text);
|
||||
}
|
||||
|
||||
(GameMain.NetworkMember.NetPeer as NetClient).SendMessage(outMsg, NetDeliveryMethod.ReliableOrdered);
|
||||
GameMain.Client.ClientPeer.Send(outMsg, DeliveryMethod.Reliable);
|
||||
}
|
||||
|
||||
//GUI stuff
|
||||
@@ -508,7 +536,7 @@ namespace Barotrauma.Networking
|
||||
var ragdollButtonBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), roundsTab.RectTransform), TextManager.Get("ServerSettingsAllowRagdollButton"));
|
||||
GetPropertyData("AllowRagdollButton").AssignGUIComponent(ragdollButtonBox);
|
||||
|
||||
var traitorRatioBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), roundsTab.RectTransform), TextManager.Get("ServerSettingsUseTraitorRatio"));
|
||||
/*var traitorRatioBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), roundsTab.RectTransform), TextManager.Get("ServerSettingsUseTraitorRatio"));
|
||||
|
||||
CreateLabeledSlider(roundsTab, "", out slider, out sliderLabel);
|
||||
var traitorRatioSlider = slider;
|
||||
@@ -553,7 +581,7 @@ namespace Barotrauma.Networking
|
||||
GetPropertyData("TraitorRatio").AssignGUIComponent(traitorRatioSlider);
|
||||
|
||||
traitorRatioSlider.OnMoved(traitorRatioSlider, traitorRatioSlider.BarScroll);
|
||||
traitorRatioBox.OnSelected(traitorRatioBox);
|
||||
traitorRatioBox.OnSelected(traitorRatioBox);*/
|
||||
|
||||
var buttonHolder = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.07f), roundsTab.RectTransform), isHorizontal: true)
|
||||
{
|
||||
@@ -829,4 +857,4 @@ namespace Barotrauma.Networking
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,70 +6,269 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Barotrauma.Steam
|
||||
{
|
||||
partial class SteamManager
|
||||
{
|
||||
private static List<string> initializationErrors = new List<string>();
|
||||
public static IEnumerable<string> InitializationErrors
|
||||
{
|
||||
get { return initializationErrors; }
|
||||
}
|
||||
public Facepunch.Steamworks.Networking Networking => client?.Networking;
|
||||
public Facepunch.Steamworks.User User => client?.User;
|
||||
public Facepunch.Steamworks.Friends Friends => client?.Friends;
|
||||
public Facepunch.Steamworks.Overlay Overlay => client?.Overlay;
|
||||
public Facepunch.Steamworks.Auth Auth => client?.Auth;
|
||||
public Facepunch.Steamworks.Lobby Lobby => client?.Lobby;
|
||||
public Facepunch.Steamworks.LobbyList LobbyList => client?.LobbyList;
|
||||
|
||||
private SteamManager()
|
||||
{
|
||||
client = null;
|
||||
isInitialized = InitializeClient();
|
||||
}
|
||||
|
||||
private bool InitializeClient()
|
||||
{
|
||||
if (client != null) { return true; }
|
||||
bool clientInitialized = false;
|
||||
try
|
||||
{
|
||||
client = new Facepunch.Steamworks.Client(AppID);
|
||||
isInitialized = client.IsSubscribed && client.IsValid;
|
||||
clientInitialized = client.IsSubscribed && client.IsValid;
|
||||
|
||||
if (isInitialized)
|
||||
if (clientInitialized)
|
||||
{
|
||||
DebugConsole.Log("Logged in as " + client.Username + " (SteamID " + client.SteamId + ")");
|
||||
DebugConsole.NewMessage("Logged in as " + client.Username + " (SteamID " + SteamIDUInt64ToString(client.SteamId) + ")");
|
||||
}
|
||||
}
|
||||
catch (DllNotFoundException)
|
||||
{
|
||||
isInitialized = false;
|
||||
clientInitialized = false;
|
||||
initializationErrors.Add("SteamDllNotFound");
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
isInitialized = false;
|
||||
clientInitialized = false;
|
||||
initializationErrors.Add("SteamClientInitFailed");
|
||||
}
|
||||
|
||||
if (!isInitialized)
|
||||
if (!clientInitialized)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
Facepunch.Steamworks.Client.Instance.Dispose();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (GameSettings.VerboseLogging) DebugConsole.ThrowError("Disposing Steam client failed.", e);
|
||||
}
|
||||
client = null;
|
||||
}
|
||||
return clientInitialized;
|
||||
}
|
||||
|
||||
private enum LobbyState
|
||||
{
|
||||
NotConnected,
|
||||
Creating,
|
||||
Owner,
|
||||
Joining,
|
||||
Joined
|
||||
}
|
||||
private static UInt64 lobbyID = 0;
|
||||
private static LobbyState lobbyState = LobbyState.NotConnected;
|
||||
private static string lobbyIP = "";
|
||||
private static Thread lobbyIPRetrievalThread;
|
||||
|
||||
private static void RetrieveLobbyIP()
|
||||
{
|
||||
//TODO: set up our own server for IP retrieval?
|
||||
|
||||
Server tempServer = null;
|
||||
try
|
||||
{
|
||||
var serverInit = new ServerInit("Barotrauma", "Barotrauma IP Retrieval")
|
||||
{
|
||||
GamePort = (ushort)27015,
|
||||
QueryPort = (ushort)27016
|
||||
};
|
||||
tempServer = new Server(AppID, serverInit, false);
|
||||
if (!tempServer.IsValid)
|
||||
{
|
||||
tempServer.Dispose();
|
||||
tempServer = null;
|
||||
DebugConsole.ThrowError("Failed to retrieve public IP: Initializing Steam server failed.");
|
||||
return;
|
||||
}
|
||||
|
||||
tempServer.LogOnAnonymous();
|
||||
lobbyIP = "";
|
||||
string error = "Timed out.";
|
||||
for (int i = 0; i < 30*60; i++)
|
||||
{
|
||||
if (instance.client.Lobby.CurrentLobby == 0)
|
||||
{
|
||||
error = "";
|
||||
break;
|
||||
}
|
||||
tempServer.Update();
|
||||
tempServer.ForceHeartbeat();
|
||||
if (tempServer.PublicIp != null)
|
||||
{
|
||||
if (instance.client.Lobby.CurrentLobby != 0)
|
||||
{
|
||||
lobbyIP = tempServer.PublicIp.ToString();
|
||||
DebugConsole.NewMessage("Successfully retrieved public IP: " + lobbyIP, Microsoft.Xna.Framework.Color.Lime);
|
||||
instance.client.Lobby.CurrentLobbyData.SetData("hostipaddress", lobbyIP);
|
||||
}
|
||||
else
|
||||
{
|
||||
error = "";
|
||||
lobbyIP = "";
|
||||
}
|
||||
break;
|
||||
}
|
||||
Thread.Sleep(16);
|
||||
}
|
||||
|
||||
tempServer.Dispose();
|
||||
tempServer = null;
|
||||
if (string.IsNullOrWhiteSpace(lobbyIP) && !string.IsNullOrWhiteSpace(error))
|
||||
{
|
||||
DebugConsole.ThrowError("Failed to retrieve public IP: "+error);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
tempServer?.Dispose();
|
||||
tempServer = null;
|
||||
}
|
||||
}
|
||||
|
||||
public static ulong GetSteamID()
|
||||
public static void CreateLobby(ServerSettings serverSettings)
|
||||
{
|
||||
if (instance == null || !instance.isInitialized)
|
||||
instance.client.Lobby.OnLobbyJoined = null;
|
||||
instance.client.Lobby.OnLobbyCreated = (success) =>
|
||||
{
|
||||
return 0;
|
||||
if (!success)
|
||||
{
|
||||
DebugConsole.ThrowError("Failed to create Steam lobby!");
|
||||
lobbyState = LobbyState.NotConnected;
|
||||
return;
|
||||
}
|
||||
|
||||
DebugConsole.NewMessage("Lobby created!", Microsoft.Xna.Framework.Color.Lime);
|
||||
|
||||
lobbyIPRetrievalThread?.Abort();
|
||||
lobbyIPRetrievalThread?.Join();
|
||||
lobbyIPRetrievalThread = null;
|
||||
lobbyIPRetrievalThread = new Thread(new ThreadStart(RetrieveLobbyIP));
|
||||
lobbyIPRetrievalThread.IsBackground = true;
|
||||
lobbyIPRetrievalThread.Start();
|
||||
|
||||
lobbyState = LobbyState.Owner;
|
||||
lobbyID = instance.client.Lobby.CurrentLobby;
|
||||
UpdateLobby(serverSettings);
|
||||
};
|
||||
if (lobbyState != LobbyState.NotConnected) { return; }
|
||||
lobbyState = LobbyState.Creating;
|
||||
instance.client.Lobby.Create(serverSettings.isPublic ? Lobby.Type.Public : Lobby.Type.FriendsOnly, serverSettings.MaxPlayers+10);
|
||||
instance.client.Lobby.Joinable = true;
|
||||
}
|
||||
|
||||
public static void UpdateLobby(ServerSettings serverSettings)
|
||||
{
|
||||
if (GameMain.Client == null)
|
||||
{
|
||||
LeaveLobby();
|
||||
}
|
||||
return instance.client.SteamId;
|
||||
|
||||
if (lobbyState == LobbyState.NotConnected)
|
||||
{
|
||||
CreateLobby(serverSettings);
|
||||
}
|
||||
|
||||
if (lobbyState != LobbyState.Owner)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var contentPackages = GameMain.Config.SelectedContentPackages.Where(cp => cp.HasMultiplayerIncompatibleContent);
|
||||
|
||||
instance.client.Lobby.Name = serverSettings.ServerName;
|
||||
instance.client.Lobby.Owner = Steam.SteamManager.GetSteamID();
|
||||
instance.client.Lobby.MaxMembers = serverSettings.MaxPlayers+10;
|
||||
instance.client.Lobby.CurrentLobbyData.SetData("playercount", (GameMain.Client?.ConnectedClients?.Count??0).ToString());
|
||||
instance.client.Lobby.CurrentLobbyData.SetData("maxplayernum", serverSettings.MaxPlayers.ToString());
|
||||
instance.client.Lobby.CurrentLobbyData.SetData("hostipaddress", lobbyIP);
|
||||
//instance.client.Lobby.CurrentLobbyData.SetData("connectsteamid", Steam.SteamManager.GetSteamID().ToString());
|
||||
instance.client.Lobby.CurrentLobbyData.SetData("haspassword", serverSettings.HasPassword.ToString());
|
||||
|
||||
instance.client.Lobby.CurrentLobbyData.SetData("message", serverSettings.ServerMessageText);
|
||||
instance.client.Lobby.CurrentLobbyData.SetData("version", GameMain.Version.ToString());
|
||||
|
||||
instance.client.Lobby.CurrentLobbyData.SetData("contentpackage", string.Join(",", contentPackages.Select(cp => cp.Name)));
|
||||
instance.client.Lobby.CurrentLobbyData.SetData("contentpackagehash", string.Join(",", contentPackages.Select(cp => cp.MD5hash.Hash)));
|
||||
instance.client.Lobby.CurrentLobbyData.SetData("contentpackageurl", string.Join(",", contentPackages.Select(cp => cp.SteamWorkshopUrl ?? "")));
|
||||
instance.client.Lobby.CurrentLobbyData.SetData("usingwhitelist", (serverSettings.Whitelist != null && serverSettings.Whitelist.Enabled).ToString());
|
||||
instance.client.Lobby.CurrentLobbyData.SetData("modeselectionmode", serverSettings.ModeSelectionMode.ToString());
|
||||
instance.client.Lobby.CurrentLobbyData.SetData("subselectionmode", serverSettings.SubSelectionMode.ToString());
|
||||
instance.client.Lobby.CurrentLobbyData.SetData("voicechatenabled", serverSettings.VoiceChatEnabled.ToString());
|
||||
instance.client.Lobby.CurrentLobbyData.SetData("allowspectating", serverSettings.AllowSpectating.ToString());
|
||||
instance.client.Lobby.CurrentLobbyData.SetData("allowrespawn", serverSettings.AllowRespawn.ToString());
|
||||
instance.client.Lobby.CurrentLobbyData.SetData("traitors", serverSettings.TraitorsEnabled.ToString());
|
||||
instance.client.Lobby.CurrentLobbyData.SetData("gamestarted", GameMain.Client.GameStarted.ToString());
|
||||
instance.client.Lobby.CurrentLobbyData.SetData("gamemode", serverSettings.GameModeIdentifier);
|
||||
|
||||
DebugConsole.NewMessage("Lobby updated!", Microsoft.Xna.Framework.Color.Lime);
|
||||
}
|
||||
|
||||
public static string GetUsername()
|
||||
public static void LeaveLobby()
|
||||
{
|
||||
if (instance == null || !instance.isInitialized)
|
||||
if (lobbyState != LobbyState.NotConnected)
|
||||
{
|
||||
return "";
|
||||
lobbyIPRetrievalThread?.Abort();
|
||||
lobbyIPRetrievalThread?.Join();
|
||||
lobbyIPRetrievalThread = null;
|
||||
|
||||
instance.client.Lobby.Leave();
|
||||
lobbyID = 0;
|
||||
lobbyIP = "";
|
||||
lobbyState = LobbyState.NotConnected;
|
||||
|
||||
instance.client.Lobby.OnLobbyJoined = null;
|
||||
}
|
||||
return instance.client.Username;
|
||||
}
|
||||
public static void JoinLobby(UInt64 id, bool joinServer)
|
||||
{
|
||||
if (instance.client.Lobby.CurrentLobby == id) { return; }
|
||||
if (lobbyID == id) { return; }
|
||||
instance.client.Lobby.OnLobbyJoined = (success) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!success)
|
||||
{
|
||||
DebugConsole.ThrowError("Failed to join Steam lobby: "+id.ToString());
|
||||
return;
|
||||
}
|
||||
lobbyState = LobbyState.Joined;
|
||||
lobbyID = instance.client.Lobby.CurrentLobby;
|
||||
if (joinServer)
|
||||
{
|
||||
GameMain.Instance.ConnectLobby = 0;
|
||||
GameMain.Instance.ConnectName = instance.client.Lobby.Name;
|
||||
GameMain.Instance.ConnectEndpoint = instance.client.Lobby.Owner.ToString();
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
instance.client.Lobby.OnLobbyJoined = null;
|
||||
}
|
||||
};
|
||||
lobbyState = LobbyState.Joining;
|
||||
lobbyID = id;
|
||||
instance.client.Lobby.Join(id);
|
||||
}
|
||||
|
||||
public static ulong GetWorkshopItemIDFromUrl(string url)
|
||||
@@ -112,13 +311,16 @@ namespace Barotrauma.Steam
|
||||
//the response is queried using the server's query port, not the game port,
|
||||
//so it may be possible to play on the server even if it doesn't respond to server list queries
|
||||
var query = instance.client.ServerList.Internet(filter);
|
||||
query.OnUpdate += () => { UpdateServerQuery(query, onServerFound, onServerRulesReceived, includeUnresponsive: true); };
|
||||
query.OnUpdate = () => { UpdateServerQuery(query, onServerFound, onServerRulesReceived, includeUnresponsive: true); };
|
||||
query.OnFinished = onFinished;
|
||||
|
||||
var localQuery = instance.client.ServerList.Local(filter);
|
||||
localQuery.OnUpdate += () => { UpdateServerQuery(localQuery, onServerFound, onServerRulesReceived, includeUnresponsive: true); };
|
||||
localQuery.OnUpdate = () => { UpdateServerQuery(localQuery, onServerFound, onServerRulesReceived, includeUnresponsive: true); };
|
||||
localQuery.OnFinished = onFinished;
|
||||
|
||||
instance.client.LobbyList.OnLobbiesUpdated = () => { UpdateLobbyQuery(onServerFound, onServerRulesReceived, onFinished); };
|
||||
instance.client.LobbyList.Refresh();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -141,7 +343,7 @@ namespace Barotrauma.Steam
|
||||
//the response is queried using the server's query port, not the game port,
|
||||
//so it may be possible to play on the server even if it doesn't respond to server list queries
|
||||
var query = instance.client.ServerList.Favourites(filter);
|
||||
query.OnUpdate += () => { UpdateServerQuery(query, onServerFound, onServerRulesReceived, includeUnresponsive: true); };
|
||||
query.OnUpdate = () => { UpdateServerQuery(query, onServerFound, onServerRulesReceived, includeUnresponsive: true); };
|
||||
query.OnFinished = onFinished;
|
||||
|
||||
return true;
|
||||
@@ -166,12 +368,71 @@ namespace Barotrauma.Steam
|
||||
//the response is queried using the server's query port, not the game port,
|
||||
//so it may be possible to play on the server even if it doesn't respond to server list queries
|
||||
var query = instance.client.ServerList.History(filter);
|
||||
query.OnUpdate += () => { UpdateServerQuery(query, onServerFound, onServerRulesReceived, includeUnresponsive: true); };
|
||||
query.OnUpdate = () => { UpdateServerQuery(query, onServerFound, onServerRulesReceived, includeUnresponsive: true); };
|
||||
query.OnFinished = onFinished;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void UpdateLobbyQuery(Action<Networking.ServerInfo> onServerFound, Action<Networking.ServerInfo> onServerRulesReceived, Action onFinished)
|
||||
{
|
||||
foreach (LobbyList.Lobby lobby in instance.client.LobbyList.Lobbies)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(lobby.GetData("haspassword"))) { continue; }
|
||||
bool.TryParse(lobby.GetData("haspassword"), out bool hasPassword);
|
||||
int.TryParse(lobby.GetData("playercount"), out int currPlayers);
|
||||
int.TryParse(lobby.GetData("maxplayernum"), out int maxPlayers);
|
||||
//UInt64.TryParse(lobby.GetData("connectsteamid"), out ulong connectSteamId);
|
||||
string ip = lobby.GetData("hostipaddress");
|
||||
if (string.IsNullOrWhiteSpace(ip)) { ip = ""; }
|
||||
|
||||
var serverInfo = new ServerInfo()
|
||||
{
|
||||
ServerName = lobby.Name,
|
||||
Port = "",
|
||||
IP = ip,
|
||||
PlayerCount = currPlayers,
|
||||
MaxPlayers = maxPlayers,
|
||||
HasPassword = hasPassword,
|
||||
RespondedToSteamQuery = true,
|
||||
LobbyID = lobby.LobbyID
|
||||
};
|
||||
serverInfo.PingChecked = false;
|
||||
serverInfo.ServerMessage = lobby.GetData("message");
|
||||
serverInfo.GameVersion = lobby.GetData("version");
|
||||
|
||||
serverInfo.ContentPackageNames.AddRange(lobby.GetData("contentpackage").Split(','));
|
||||
serverInfo.ContentPackageHashes.AddRange(lobby.GetData("contentpackagehash").Split(','));
|
||||
serverInfo.ContentPackageWorkshopUrls.AddRange(lobby.GetData("contentpackageurl").Split(','));
|
||||
|
||||
serverInfo.UsingWhiteList = lobby.GetData("usingwhitelist") == "True";
|
||||
SelectionMode selectionMode;
|
||||
if (Enum.TryParse(lobby.GetData("modeselectionmode"), out selectionMode)) serverInfo.ModeSelectionMode = selectionMode;
|
||||
if (Enum.TryParse(lobby.GetData("subselectionmode"), out selectionMode)) serverInfo.SubSelectionMode = selectionMode;
|
||||
|
||||
serverInfo.AllowSpectating = lobby.GetData("allowspectating") == "True";
|
||||
serverInfo.AllowRespawn = lobby.GetData("allowrespawn") == "True";
|
||||
serverInfo.VoipEnabled = lobby.GetData("voicechatenabled") == "True";
|
||||
if (Enum.TryParse(lobby.GetData("traitors"), out YesNoMaybe traitorsEnabled)) serverInfo.TraitorsEnabled = traitorsEnabled;
|
||||
|
||||
serverInfo.GameStarted = lobby.GetData("gamestarted") == "True";
|
||||
serverInfo.GameMode = lobby.GetData("gamemode");
|
||||
|
||||
if (serverInfo.ContentPackageNames.Count != serverInfo.ContentPackageHashes.Count ||
|
||||
serverInfo.ContentPackageHashes.Count != serverInfo.ContentPackageWorkshopUrls.Count)
|
||||
{
|
||||
//invalid contentpackage info
|
||||
serverInfo.ContentPackageNames.Clear();
|
||||
serverInfo.ContentPackageHashes.Clear();
|
||||
}
|
||||
|
||||
onServerFound(serverInfo);
|
||||
//onServerRulesReceived(serverInfo);
|
||||
}
|
||||
|
||||
onFinished();
|
||||
}
|
||||
|
||||
private static void UpdateServerQuery(ServerList.Request query, Action<Networking.ServerInfo> onServerFound, Action<Networking.ServerInfo> onServerRulesReceived, bool includeUnresponsive)
|
||||
{
|
||||
IEnumerable<ServerList.Server> servers = includeUnresponsive ?
|
||||
@@ -191,6 +452,9 @@ namespace Barotrauma.Steam
|
||||
{
|
||||
DebugConsole.Log(s.Name + " did not respond to server query.");
|
||||
}
|
||||
|
||||
if (s.Description == "Barotrauma IP Retrieval") { continue; }
|
||||
|
||||
var serverInfo = new ServerInfo()
|
||||
{
|
||||
ServerName = s.Name,
|
||||
@@ -203,6 +467,7 @@ namespace Barotrauma.Steam
|
||||
};
|
||||
serverInfo.PingChecked = true;
|
||||
serverInfo.Ping = s.Ping;
|
||||
serverInfo.LobbyID = 0;
|
||||
if (responded)
|
||||
{
|
||||
s.FetchRules();
|
||||
@@ -210,7 +475,7 @@ namespace Barotrauma.Steam
|
||||
s.OnReceivedRules += (bool rulesReceived) =>
|
||||
{
|
||||
if (!rulesReceived || s.Rules == null) { return; }
|
||||
|
||||
|
||||
if (s.Rules.ContainsKey("message")) serverInfo.ServerMessage = s.Rules["message"];
|
||||
if (s.Rules.ContainsKey("version")) serverInfo.GameVersion = s.Rules["version"];
|
||||
|
||||
@@ -270,6 +535,7 @@ namespace Barotrauma.Steam
|
||||
return true;
|
||||
}
|
||||
|
||||
private static Auth.Ticket currentTicket = null;
|
||||
public static Auth.Ticket GetAuthSessionTicket()
|
||||
{
|
||||
if (instance == null || !instance.isInitialized)
|
||||
@@ -277,17 +543,39 @@ namespace Barotrauma.Steam
|
||||
return null;
|
||||
}
|
||||
|
||||
return instance.client.Auth.GetAuthSessionTicket();
|
||||
currentTicket?.Cancel();
|
||||
currentTicket = instance.client.Auth.GetAuthSessionTicket();
|
||||
return currentTicket;
|
||||
}
|
||||
|
||||
public static ClientStartAuthSessionResult StartAuthSession(byte[] authTicketData, ulong clientSteamID)
|
||||
{
|
||||
if (instance == null || !instance.isInitialized || instance.client == null) return ClientStartAuthSessionResult.ServerNotConnectedToSteam;
|
||||
|
||||
DebugConsole.NewMessage("SteamManager authenticating Steam client " + clientSteamID);
|
||||
ClientStartAuthSessionResult startResult = instance.client.Auth.StartSession(authTicketData, clientSteamID);
|
||||
if (startResult != ClientStartAuthSessionResult.OK)
|
||||
{
|
||||
DebugConsole.NewMessage("Authentication failed: failed to start auth session (" + startResult.ToString() + ")");
|
||||
}
|
||||
|
||||
return startResult;
|
||||
}
|
||||
|
||||
public static void StopAuthSession(ulong clientSteamID)
|
||||
{
|
||||
if (instance == null || !instance.isInitialized || instance.client == null) return;
|
||||
|
||||
DebugConsole.NewMessage("SteamManager ending auth session with Steam client " + clientSteamID);
|
||||
instance.client.Auth.EndSession(clientSteamID);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Workshop
|
||||
|
||||
public const string WorkshopItemStagingFolder = "NewWorkshopItem";
|
||||
|
||||
public const string WorkshopItemPreviewImageFolder = "Workshop";
|
||||
public const string PreviewImageName = "PreviewImage.png";
|
||||
private const string MetadataFileName = "filelist.xml";
|
||||
public const string DefaultPreviewImagePath = "Content/DefaultWorkshopPreviewImage.png";
|
||||
|
||||
private Sprite defaultPreviewImage;
|
||||
@@ -404,54 +692,45 @@ namespace Barotrauma.Steam
|
||||
item.Subscribe();
|
||||
item.Download();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new folder, copies the specified files there and creates a metadata file with install instructions.
|
||||
/// </summary>
|
||||
public static void CreateWorkshopItemStaging(List<ContentFile> contentFiles, out Workshop.Editor itemEditor, out ContentPackage contentPackage)
|
||||
|
||||
public static void CreateWorkshopItemStaging(ContentPackage contentPackage, out Workshop.Editor itemEditor)
|
||||
{
|
||||
var stagingFolder = new DirectoryInfo(WorkshopItemStagingFolder);
|
||||
if (stagingFolder.Exists)
|
||||
itemEditor = instance.client.Workshop.CreateItem(Workshop.ItemType.Community);
|
||||
itemEditor.Visibility = Workshop.Editor.VisibilityType.Public;
|
||||
itemEditor.WorkshopUploadAppId = AppID;
|
||||
itemEditor.Folder = Path.GetFullPath(Path.GetDirectoryName(contentPackage.Path));
|
||||
|
||||
string previewImagePath = Path.GetFullPath(Path.Combine(itemEditor.Folder, PreviewImageName));
|
||||
if (!Directory.Exists(itemEditor.Folder)) { Directory.CreateDirectory(itemEditor.Folder); }
|
||||
if (!File.Exists(previewImagePath))
|
||||
{
|
||||
SaveUtil.ClearFolder(stagingFolder.FullName);
|
||||
File.Copy("Content/DefaultWorkshopPreviewImage.png", previewImagePath);
|
||||
}
|
||||
else
|
||||
{
|
||||
stagingFolder.Create();
|
||||
}
|
||||
Directory.CreateDirectory(Path.Combine(WorkshopItemStagingFolder, "Submarines"));
|
||||
Directory.CreateDirectory(Path.Combine(WorkshopItemStagingFolder, "Mods"));
|
||||
Directory.CreateDirectory(Path.Combine(WorkshopItemStagingFolder, "Mods", "ModName"));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new empty content package
|
||||
/// </summary>
|
||||
public static void CreateWorkshopItemStaging(string itemName, out Workshop.Editor itemEditor, out ContentPackage contentPackage)
|
||||
{
|
||||
string dirPath = Path.Combine("Mods", ToolBox.RemoveInvalidFileNameChars(itemName));
|
||||
Directory.CreateDirectory("Mods");
|
||||
Directory.CreateDirectory(dirPath);
|
||||
|
||||
itemEditor = instance.client.Workshop.CreateItem(Workshop.ItemType.Community);
|
||||
itemEditor.Visibility = Workshop.Editor.VisibilityType.Public;
|
||||
itemEditor.WorkshopUploadAppId = AppID;
|
||||
itemEditor.Folder = stagingFolder.FullName;
|
||||
itemEditor.Folder = dirPath;
|
||||
|
||||
string previewImagePath = Path.GetFullPath(Path.Combine(itemEditor.Folder, PreviewImageName));
|
||||
File.Copy("Content/DefaultWorkshopPreviewImage.png", previewImagePath);
|
||||
|
||||
//copy content files to the staging folder
|
||||
List<string> copiedFilePaths = new List<string>();
|
||||
foreach (ContentFile file in contentFiles)
|
||||
string previewImagePath = Path.GetFullPath(Path.Combine(dirPath, PreviewImageName));
|
||||
if (!File.Exists(previewImagePath))
|
||||
{
|
||||
string relativePath = UpdaterUtil.GetRelativePath(Path.GetFullPath(file.Path), Environment.CurrentDirectory);
|
||||
string destinationPath = Path.Combine(stagingFolder.FullName, relativePath);
|
||||
//make sure the directory exists
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(destinationPath));
|
||||
File.Copy(file.Path, destinationPath);
|
||||
copiedFilePaths.Add(destinationPath);
|
||||
File.Copy("Content/DefaultWorkshopPreviewImage.png", previewImagePath);
|
||||
}
|
||||
System.Diagnostics.Debug.Assert(copiedFilePaths.Count == contentFiles.Count);
|
||||
|
||||
|
||||
//create a new content package and include the copied files in it
|
||||
contentPackage = ContentPackage.CreatePackage("ContentPackage", Path.Combine(itemEditor.Folder, MetadataFileName), false);
|
||||
for (int i = 0; i < copiedFilePaths.Count; i++)
|
||||
{
|
||||
contentPackage.AddFile(copiedFilePaths[i], contentFiles[i].Type);
|
||||
}
|
||||
|
||||
contentPackage.Save(Path.Combine(stagingFolder.FullName, MetadataFileName));
|
||||
contentPackage = ContentPackage.CreatePackage(itemName, Path.Combine(dirPath, MetadataFileName), false);
|
||||
contentPackage.Save(Path.Combine(dirPath, MetadataFileName));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -467,23 +746,67 @@ namespace Barotrauma.Steam
|
||||
return;
|
||||
}
|
||||
|
||||
var stagingFolder = new DirectoryInfo(WorkshopItemStagingFolder);
|
||||
if (stagingFolder.Exists)
|
||||
{
|
||||
SaveUtil.ClearFolder(stagingFolder.FullName);
|
||||
}
|
||||
else
|
||||
{
|
||||
stagingFolder.Create();
|
||||
}
|
||||
|
||||
itemEditor = instance.client.Workshop.EditItem(existingItem.Id);
|
||||
itemEditor.Visibility = Workshop.Editor.VisibilityType.Public;
|
||||
itemEditor.Title = existingItem.Title;
|
||||
itemEditor.Tags = existingItem.Tags.ToList();
|
||||
itemEditor.Description = existingItem.Description;
|
||||
itemEditor.WorkshopUploadAppId = AppID;
|
||||
itemEditor.Folder = stagingFolder.FullName;
|
||||
|
||||
if (!CheckWorkshopItemEnabled(existingItem, checkContentFiles: false))
|
||||
{
|
||||
if (!EnableWorkShopItem(existingItem, false, out string errorMsg))
|
||||
{
|
||||
DebugConsole.ThrowError(errorMsg);
|
||||
new GUIMessageBox(
|
||||
TextManager.Get("Error"),
|
||||
TextManager.GetWithVariables("WorkshopItemUpdateFailed", new string[2] { "[itemname]", "[errormessage]" }, new string[2] { existingItem.Title, errorMsg }));
|
||||
itemEditor = null;
|
||||
contentPackage = null;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ContentPackage tempContentPackage = new ContentPackage(Path.Combine(existingItem.Directory.FullName, MetadataFileName));
|
||||
string installedContentPackagePath = Path.GetFullPath(GetWorkshopItemContentPackagePath(tempContentPackage));
|
||||
contentPackage = ContentPackage.List.Find(cp => Path.GetFullPath(cp.Path) == installedContentPackagePath);
|
||||
if (tempContentPackage.GameVersion > new Version(0, 9, 1, 0))
|
||||
{
|
||||
itemEditor.Folder = Path.GetDirectoryName(installedContentPackagePath);
|
||||
}
|
||||
else //legacy support
|
||||
{
|
||||
try
|
||||
{
|
||||
tempContentPackage.GameVersion = GameMain.Version;
|
||||
string newPath = GetWorkshopItemContentPackagePath(tempContentPackage);
|
||||
string newDir = Path.GetDirectoryName(newPath);
|
||||
contentPackage.Path = newPath;
|
||||
itemEditor.Folder = newDir;
|
||||
if (!Directory.Exists(newDir)) { Directory.CreateDirectory(newDir); }
|
||||
File.Move(installedContentPackagePath, newPath);
|
||||
//move all files inside the Mods folder
|
||||
foreach (ContentFile cf in contentPackage.Files)
|
||||
{
|
||||
string relativePath = UpdaterUtil.GetRelativePath(Path.GetFullPath(cf.Path), Path.GetFullPath(newDir));
|
||||
if (relativePath.StartsWith(".."))
|
||||
{
|
||||
string destinationPath = Path.Combine(newDir, cf.Path);
|
||||
if (!Directory.Exists(Path.GetDirectoryName(destinationPath))) { Directory.CreateDirectory(Path.GetDirectoryName(destinationPath)); }
|
||||
File.Move(cf.Path, destinationPath);
|
||||
cf.Path = destinationPath;
|
||||
}
|
||||
}
|
||||
contentPackage.Save(contentPackage.Path);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
string errorMsg = TextManager.GetWithVariable("WorkshopErrorOnEnable", "[itemname]", TextManager.EnsureUTF8(existingItem.Title));
|
||||
new GUIMessageBox(TextManager.Get("Error"), errorMsg);
|
||||
DebugConsole.ThrowError(errorMsg, e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
string previewImagePath = Path.GetFullPath(Path.Combine(itemEditor.Folder, PreviewImageName));
|
||||
itemEditor.PreviewImage = previewImagePath;
|
||||
@@ -512,46 +835,6 @@ namespace Barotrauma.Steam
|
||||
GameAnalyticsManager.AddErrorEventOnce("SteamManager.CreateWorkshopItemStaging:WriteAllBytesFailed" + previewImagePath,
|
||||
GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg + "\n" + e.Message);
|
||||
}
|
||||
|
||||
ContentPackage tempContentPackage = new ContentPackage(Path.Combine(existingItem.Directory.FullName, MetadataFileName));
|
||||
//item already installed, copy it from the game folder
|
||||
if (existingItem != null && CheckWorkshopItemEnabled(existingItem, checkContentFiles: false))
|
||||
{
|
||||
string installedItemPath = GetWorkshopItemContentPackagePath(tempContentPackage);
|
||||
if (File.Exists(installedItemPath))
|
||||
{
|
||||
tempContentPackage = new ContentPackage(installedItemPath);
|
||||
}
|
||||
}
|
||||
if (File.Exists(tempContentPackage.Path))
|
||||
{
|
||||
string newContentPackagePath = Path.Combine(WorkshopItemStagingFolder, MetadataFileName);
|
||||
File.Copy(tempContentPackage.Path, newContentPackagePath, overwrite: true);
|
||||
contentPackage = new ContentPackage(newContentPackagePath);
|
||||
foreach (ContentFile contentFile in tempContentPackage.Files)
|
||||
{
|
||||
string sourceFile;
|
||||
if (contentFile.Type == ContentType.Submarine && File.Exists(contentFile.Path))
|
||||
{
|
||||
sourceFile = contentFile.Path;
|
||||
}
|
||||
else
|
||||
{
|
||||
sourceFile = Path.Combine(existingItem.Directory.FullName, contentFile.Path);
|
||||
}
|
||||
if (!File.Exists(sourceFile)) { continue; }
|
||||
//make sure the destination directory exists
|
||||
string destinationPath = Path.Combine(WorkshopItemStagingFolder, contentFile.Path);
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(destinationPath));
|
||||
File.Copy(sourceFile, destinationPath, overwrite: true);
|
||||
contentPackage.AddFile(contentFile.Path, contentFile.Type);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
contentPackage = ContentPackage.CreatePackage(existingItem.Title, Path.Combine(WorkshopItemStagingFolder, MetadataFileName), false);
|
||||
contentPackage.Save(contentPackage.Path);
|
||||
}
|
||||
}
|
||||
|
||||
public static void StartPublishItem(ContentPackage contentPackage, Workshop.Editor item)
|
||||
@@ -568,12 +851,11 @@ namespace Barotrauma.Steam
|
||||
DebugConsole.ThrowError("Cannot publish workshop item \"" + item.Title + "\" - folder not set.");
|
||||
return;
|
||||
}
|
||||
|
||||
contentPackage.Name = item.Title;
|
||||
|
||||
contentPackage.GameVersion = GameMain.Version;
|
||||
contentPackage.Save(Path.Combine(WorkshopItemStagingFolder, MetadataFileName));
|
||||
contentPackage.Save(contentPackage.Path);
|
||||
|
||||
if (File.Exists(PreviewImageName)) File.Delete(PreviewImageName);
|
||||
if (File.Exists(PreviewImageName)) { File.Delete(PreviewImageName); }
|
||||
//move the preview image out of the staging folder, it does not need to be included in the folder sent to Workshop
|
||||
File.Move(Path.GetFullPath(Path.Combine(item.Folder, PreviewImageName)), PreviewImageName);
|
||||
item.PreviewImage = Path.GetFullPath(PreviewImageName);
|
||||
@@ -604,18 +886,7 @@ namespace Barotrauma.Steam
|
||||
{
|
||||
DebugConsole.NewMessage("Publishing workshop item " + item.Title + " failed. " + item.Error, Microsoft.Xna.Framework.Color.Red);
|
||||
}
|
||||
|
||||
SaveUtil.ClearFolder(WorkshopItemStagingFolder);
|
||||
File.Delete(PreviewImageName);
|
||||
try
|
||||
{
|
||||
Directory.Delete(WorkshopItemStagingFolder);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
DebugConsole.ThrowError("Failed to delete Workshop item staging folder.", e);
|
||||
}
|
||||
|
||||
|
||||
yield return CoroutineStatus.Success;
|
||||
}
|
||||
|
||||
@@ -632,6 +903,14 @@ namespace Barotrauma.Steam
|
||||
}
|
||||
|
||||
string metaDataFilePath = Path.Combine(item.Directory.FullName, MetadataFileName);
|
||||
|
||||
if (!File.Exists(metaDataFilePath))
|
||||
{
|
||||
errorMsg = TextManager.GetWithVariable("WorkshopErrorInstallRequiredToEnable", "[itemname]", item.Title);
|
||||
DebugConsole.ThrowError(errorMsg);
|
||||
return false;
|
||||
}
|
||||
|
||||
ContentPackage contentPackage = new ContentPackage(metaDataFilePath);
|
||||
string newContentPackagePath = GetWorkshopItemContentPackagePath(contentPackage);
|
||||
|
||||
@@ -644,11 +923,52 @@ namespace Barotrauma.Steam
|
||||
|
||||
if (contentPackage.CorePackage && !contentPackage.ContainsRequiredCorePackageFiles(out List<ContentType> missingContentTypes))
|
||||
{
|
||||
errorMsg = TextManager.GetWithVariables("ContentPackageMissingCoreFiles", new string[2] { "[packagename]", "[missingfiletypes]" },
|
||||
errorMsg = TextManager.GetWithVariables("ContentPackageMissingCoreFiles", new string[2] { "[packagename]", "[missingfiletypes]" },
|
||||
new string[2] { contentPackage.Name, string.Join(", ", missingContentTypes) }, new bool[2] { false, true });
|
||||
return false;
|
||||
}
|
||||
|
||||
if (contentPackage.GameVersion > new Version(0, 9, 1, 0))
|
||||
{
|
||||
SaveUtil.CopyFolder(item.Directory.FullName, Path.GetDirectoryName(GetWorkshopItemContentPackagePath(contentPackage)), copySubDirs: true, overwriteExisting: true);
|
||||
}
|
||||
else //legacy support
|
||||
{
|
||||
EnableWorkShopItemLegacy(item, contentPackage, newContentPackagePath, metaDataFilePath, allowFileOverwrite, out errorMsg);
|
||||
}
|
||||
|
||||
var newPackage = new ContentPackage(contentPackage.Path, newContentPackagePath)
|
||||
{
|
||||
SteamWorkshopUrl = item.Url,
|
||||
InstallTime = item.Modified > item.Created ? item.Modified : item.Created
|
||||
};
|
||||
if (!Directory.Exists(Path.GetDirectoryName(newContentPackagePath)))
|
||||
{
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(newContentPackagePath));
|
||||
}
|
||||
newPackage.Save(newContentPackagePath);
|
||||
ContentPackage.List.Add(newPackage);
|
||||
if (newPackage.CorePackage)
|
||||
{
|
||||
//if enabling a core package, disable all other core packages
|
||||
GameMain.Config.SelectedContentPackages.RemoveWhere(cp => cp.CorePackage);
|
||||
}
|
||||
GameMain.Config.SelectedContentPackages.Add(newPackage);
|
||||
GameMain.Config.SaveNewPlayerConfig();
|
||||
|
||||
if (newPackage.Files.Any(f => f.Type == ContentType.Submarine))
|
||||
{
|
||||
Submarine.RefreshSavedSubs();
|
||||
}
|
||||
|
||||
errorMsg = "";
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool EnableWorkShopItemLegacy(Workshop.Item item, ContentPackage contentPackage, string newContentPackagePath, string metaDataFilePath, bool allowFileOverwrite, out string errorMsg)
|
||||
{
|
||||
errorMsg = "";
|
||||
|
||||
var allPackageFiles = Directory.GetFiles(item.Directory.FullName, "*", SearchOption.AllDirectories);
|
||||
List<string> nonContentFiles = new List<string>();
|
||||
foreach (string file in allPackageFiles)
|
||||
@@ -748,27 +1068,6 @@ namespace Barotrauma.Steam
|
||||
return false;
|
||||
}
|
||||
|
||||
var newPackage = new ContentPackage(contentPackage.Path, newContentPackagePath)
|
||||
{
|
||||
SteamWorkshopUrl = item.Url,
|
||||
InstallTime = item.Modified > item.Created ? item.Modified : item.Created
|
||||
};
|
||||
newPackage.Save(newContentPackagePath);
|
||||
ContentPackage.List.Add(newPackage);
|
||||
if (newPackage.CorePackage)
|
||||
{
|
||||
//if enabling a core package, disable all other core packages
|
||||
GameMain.Config.SelectedContentPackages.RemoveWhere(cp => cp.CorePackage);
|
||||
}
|
||||
GameMain.Config.SelectedContentPackages.Add(newPackage);
|
||||
GameMain.Config.SaveNewPlayerConfig();
|
||||
|
||||
if (newPackage.Files.Any(f => f.Type == ContentType.Submarine))
|
||||
{
|
||||
Submarine.RefreshSavedSubs();
|
||||
}
|
||||
|
||||
errorMsg = "";
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -894,7 +1193,14 @@ namespace Barotrauma.Steam
|
||||
|
||||
public static bool CheckWorkshopItemEnabled(Workshop.Item item, bool checkContentFiles = true)
|
||||
{
|
||||
if (!item.Installed) return false;
|
||||
if (!item.Installed) { return false; }
|
||||
|
||||
if (!Directory.Exists(item.Directory.FullName))
|
||||
{
|
||||
DebugConsole.ThrowError("Workshop item \"" + item.Title + "\" has been installed but the install directory cannot be found. Attempting to redownload...");
|
||||
item.ForceDownload();
|
||||
return false;
|
||||
}
|
||||
|
||||
string metaDataPath = Path.Combine(item.Directory.FullName, MetadataFileName);
|
||||
if (!File.Exists(metaDataPath))
|
||||
@@ -1004,10 +1310,11 @@ namespace Barotrauma.Steam
|
||||
|
||||
public static string GetWorkshopItemContentPackagePath(ContentPackage contentPackage)
|
||||
{
|
||||
string fileName = contentPackage.Name + ".xml";
|
||||
string invalidChars = new string(Path.GetInvalidFileNameChars()) + new string(Path.GetInvalidPathChars());
|
||||
foreach (char c in invalidChars) fileName = fileName.Replace(c.ToString(), "");
|
||||
return Path.Combine("Data", "ContentPackages", fileName);
|
||||
string fileName = contentPackage.Name;
|
||||
string invalidChars = ToolBox.RemoveInvalidFileNameChars(fileName);
|
||||
return contentPackage.GameVersion > new Version(0, 9, 1, 0) ?
|
||||
Path.Combine("Mods", fileName, MetadataFileName) :
|
||||
Path.Combine("Data", "ContentPackages", fileName + ".xml"); //legacy support
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Lidgren.Network;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework;
|
||||
using OpenAL;
|
||||
using System;
|
||||
using System.Linq;
|
||||
@@ -97,7 +96,8 @@ namespace Barotrauma.Networking
|
||||
UserData = "capturedevicenotfound"
|
||||
};
|
||||
}
|
||||
GameAnalyticsManager.AddErrorEventOnce("Alc.CaptureDeviceOpen(" + deviceName + ") failed", GameAnalyticsSDK.Net.EGAErrorSeverity.Error,"Error code: "+errorCode);
|
||||
GameAnalyticsManager.AddErrorEventOnce("Alc.CaptureDeviceOpenFailed", GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
|
||||
"Alc.CaptureDeviceOpen(" + deviceName + ") failed. Error code: " + errorCode);
|
||||
GameMain.Config.VoiceSetting = GameSettings.VoiceMode.Disabled;
|
||||
Instance?.Dispose();
|
||||
Instance = null;
|
||||
@@ -234,7 +234,7 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
|
||||
public override void Write(NetBuffer msg)
|
||||
public override void Write(IWriteMessage msg)
|
||||
{
|
||||
lock (buffers)
|
||||
{
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Barotrauma.Sounds;
|
||||
using Lidgren.Network;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
@@ -13,13 +12,13 @@ namespace Barotrauma.Networking
|
||||
class VoipClient : IDisposable
|
||||
{
|
||||
private GameClient gameClient;
|
||||
private NetClient netClient;
|
||||
private ClientPeer netClient;
|
||||
private DateTime lastSendTime;
|
||||
private List<VoipQueue> queues;
|
||||
|
||||
private UInt16 storedBufferID = 0;
|
||||
|
||||
public VoipClient(GameClient gClient,NetClient nClient)
|
||||
public VoipClient(GameClient gClient,ClientPeer nClient)
|
||||
{
|
||||
gameClient = gClient;
|
||||
netClient = nClient;
|
||||
@@ -59,19 +58,19 @@ namespace Barotrauma.Networking
|
||||
|
||||
if (DateTime.Now >= lastSendTime + VoipConfig.SEND_INTERVAL)
|
||||
{
|
||||
NetOutgoingMessage msg = netClient.CreateMessage();
|
||||
IWriteMessage msg = new WriteOnlyMessage();
|
||||
|
||||
msg.Write((byte)ClientPacketHeader.VOICE);
|
||||
msg.Write((byte)VoipCapture.Instance.QueueID);
|
||||
VoipCapture.Instance.Write(msg);
|
||||
|
||||
netClient.SendMessage(msg, NetDeliveryMethod.Unreliable);
|
||||
netClient.Send(msg, DeliveryMethod.Unreliable);
|
||||
|
||||
lastSendTime = DateTime.Now;
|
||||
}
|
||||
}
|
||||
|
||||
public void Read(NetBuffer msg)
|
||||
public void Read(IReadMessage msg)
|
||||
{
|
||||
byte queueId = msg.ReadByte();
|
||||
VoipQueue queue = queues.Find(q => q.QueueID == queueId);
|
||||
@@ -95,7 +94,7 @@ namespace Barotrauma.Networking
|
||||
client.VoipSound = new VoipSound(GameMain.SoundManager, client.VoipQueue);
|
||||
}
|
||||
|
||||
if (client.Character != null && !client.Character.IsDead && !client.Character.IsDead && client.Character.SpeechImpediment <= 100.0f)
|
||||
if (client.Character != null && !client.Character.IsDead && client.Character.SpeechImpediment <= 100.0f)
|
||||
{
|
||||
var messageType = ChatMessage.CanUseRadio(client.Character, out WifiComponent radio) ? ChatMessageType.Radio : ChatMessageType.Default;
|
||||
client.Character.ShowSpeechBubble(1.25f, ChatMessage.MessageColor[(int)messageType]);
|
||||
@@ -114,8 +113,27 @@ namespace Barotrauma.Networking
|
||||
client.VoipSound.UseMuffleFilter = SoundPlayer.ShouldMuffleSound(Character.Controlled, client.Character.WorldPosition, ChatMessage.SpeakRange, client.Character.CurrentHull);
|
||||
}
|
||||
}
|
||||
GameMain.NetLobbyScreen.SetPlayerSpeaking(client);
|
||||
|
||||
GameMain.NetLobbyScreen?.SetPlayerSpeaking(client);
|
||||
GameMain.GameSession?.CrewManager?.SetClientSpeaking(client);
|
||||
|
||||
if (client.VoipSound.CurrentAmplitude > 0.1f) //TODO: might need to tweak
|
||||
{
|
||||
if (client.Character != null)
|
||||
{
|
||||
Vector3 clientPos = new Vector3(client.Character.WorldPosition.X, client.Character.WorldPosition.Y, 0.0f);
|
||||
Vector3 listenerPos = GameMain.SoundManager.ListenerPosition;
|
||||
float attenuationDist = client.VoipSound.Near * 1.125f;
|
||||
if (Vector3.DistanceSquared(clientPos, listenerPos) < attenuationDist * attenuationDist)
|
||||
{
|
||||
GameMain.SoundManager.VoipAttenuatedGain = 0.5f;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
GameMain.SoundManager.VoipAttenuatedGain = 0.5f;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Barotrauma.Networking;
|
||||
using Lidgren.Network;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
@@ -105,7 +104,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public void ClientWrite(NetBuffer msg, VoteType voteType, object data)
|
||||
public void ClientWrite(IWriteMessage msg, VoteType voteType, object data)
|
||||
{
|
||||
msg.Write((byte)voteType);
|
||||
|
||||
@@ -141,7 +140,7 @@ namespace Barotrauma
|
||||
msg.WritePadBits();
|
||||
}
|
||||
|
||||
public void ClientRead(NetBuffer inc)
|
||||
public void ClientRead(IReadMessage inc)
|
||||
{
|
||||
AllowSubVoting = inc.ReadBoolean();
|
||||
if (allowSubVoting)
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Lidgren.Network;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
@@ -177,7 +176,7 @@ namespace Barotrauma.Networking
|
||||
return true;
|
||||
}
|
||||
|
||||
public void ClientAdminRead(NetBuffer incMsg)
|
||||
public void ClientAdminRead(IReadMessage incMsg)
|
||||
{
|
||||
bool hasPermission = incMsg.ReadBoolean();
|
||||
if (!hasPermission)
|
||||
@@ -192,8 +191,8 @@ namespace Barotrauma.Networking
|
||||
incMsg.ReadPadBits();
|
||||
|
||||
whitelistedPlayers.Clear();
|
||||
Int32 bannedPlayerCount = incMsg.ReadVariableInt32();
|
||||
for (int i = 0; i < bannedPlayerCount; i++)
|
||||
UInt32 bannedPlayerCount = incMsg.ReadVariableUInt32();
|
||||
for (int i = 0; i < (int)bannedPlayerCount; i++)
|
||||
{
|
||||
string name = incMsg.ReadString();
|
||||
UInt16 uniqueIdentifier = incMsg.ReadUInt16();
|
||||
@@ -216,7 +215,7 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
|
||||
public void ClientAdminWrite(NetBuffer outMsg)
|
||||
public void ClientAdminWrite(IWriteMessage outMsg)
|
||||
{
|
||||
outMsg.Write(localEnabled);
|
||||
outMsg.WritePadBits();
|
||||
|
||||
@@ -144,7 +144,7 @@ namespace Barotrauma
|
||||
1.0f / bodyShapeTextureScale, SpriteEffects.None, 0.0f);
|
||||
}
|
||||
|
||||
public PosInfo ClientRead(ServerNetObject type, NetBuffer msg, float sendingTime, string parentDebugName)
|
||||
public PosInfo ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime, string parentDebugName)
|
||||
{
|
||||
float MaxVel = NetConfig.MaxPhysicsBodyVelocity;
|
||||
float MaxAngularVel = NetConfig.MaxPhysicsBodyAngularVelocity;
|
||||
@@ -156,8 +156,8 @@ namespace Barotrauma
|
||||
float? newAngularVelocity = null;
|
||||
|
||||
newPosition = new Vector2(
|
||||
msg.ReadFloat(),
|
||||
msg.ReadFloat());
|
||||
msg.ReadSingle(),
|
||||
msg.ReadSingle());
|
||||
|
||||
awake = msg.ReadBoolean();
|
||||
bool fixedRotation = msg.ReadBoolean();
|
||||
|
||||
@@ -599,7 +599,8 @@ namespace Barotrauma
|
||||
if (!tb.Selected) { return false; }
|
||||
RefreshMissionTab(tb.UserData as Mission);
|
||||
Campaign.Map.OnMissionSelected?.Invoke(connection, mission);
|
||||
if (GameMain.Client != null && GameMain.Client.HasPermission(Networking.ClientPermissions.ManageCampaign))
|
||||
if ((Campaign is MultiPlayerCampaign multiPlayerCampaign) && !multiPlayerCampaign.SuppressStateSending &&
|
||||
GameMain.Client != null && GameMain.Client.HasPermission(Networking.ClientPermissions.ManageCampaign))
|
||||
{
|
||||
GameMain.Client?.SendCampaignState();
|
||||
}
|
||||
|
||||
@@ -97,7 +97,7 @@ namespace Barotrauma
|
||||
|
||||
SoundPlayer.OverrideMusicType = "none";
|
||||
SoundPlayer.OverrideMusicDuration = null;
|
||||
GameMain.SoundManager.SetCategoryGainMultiplier("waterambience", 0.0f);
|
||||
GameMain.SoundManager.SetCategoryGainMultiplier("waterambience", 0.0f, 0);
|
||||
|
||||
GUI.ForceMouseOn(null);
|
||||
CalculateSpritesheetPosition();
|
||||
@@ -195,7 +195,7 @@ namespace Barotrauma
|
||||
base.Deselect();
|
||||
|
||||
SoundPlayer.OverrideMusicType = null;
|
||||
GameMain.SoundManager.SetCategoryGainMultiplier("waterambience", GameMain.Config.SoundVolume);
|
||||
GameMain.SoundManager.SetCategoryGainMultiplier("waterambience", GameMain.Config.SoundVolume, 0);
|
||||
|
||||
GUI.ForceMouseOn(null);
|
||||
if (isEndlessRunner)
|
||||
@@ -1467,6 +1467,7 @@ namespace Barotrauma
|
||||
|
||||
private void ShowWearables()
|
||||
{
|
||||
if (character.Inventory == null) { return; }
|
||||
foreach (var item in character.Inventory.Items)
|
||||
{
|
||||
if (item == null) { continue; }
|
||||
@@ -1478,7 +1479,7 @@ namespace Barotrauma
|
||||
|
||||
private void HideWearables()
|
||||
{
|
||||
character.Inventory.Items.ForEachMod(i => i?.Unequip(character));
|
||||
character.Inventory?.Items.ForEachMod(i => i?.Unequip(character));
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
@@ -23,8 +23,8 @@ namespace Barotrauma
|
||||
|
||||
private CampaignSetupUI campaignSetupUI;
|
||||
|
||||
private GUITextBox serverNameBox, portBox, queryPortBox, passwordBox, maxPlayersBox;
|
||||
private GUITickBox isPublicBox, useUpnpBox;
|
||||
private GUITextBox serverNameBox, /*portBox, queryPortBox,*/ passwordBox, maxPlayersBox;
|
||||
private GUITickBox isPublicBox/*, useUpnpBox*/;
|
||||
|
||||
private GUIButton joinServerButton, hostServerButton, steamWorkshopButton;
|
||||
|
||||
@@ -203,10 +203,6 @@ namespace Barotrauma
|
||||
UserData = Tab.SteamWorkshop,
|
||||
OnClicked = SelectTab
|
||||
};
|
||||
|
||||
/*#if OSX && !DEBUG
|
||||
steamWorkshopButton.Text += " (Not yet available on MacOS)";
|
||||
#endif*/
|
||||
}
|
||||
|
||||
new GUIButton(new RectTransform(new Vector2(1.0f, 1.0f), customizeList.RectTransform), TextManager.Get("SubEditorButton"), textAlignment: Alignment.Left, style: "MainMenuGUIButton")
|
||||
@@ -256,7 +252,7 @@ namespace Barotrauma
|
||||
UserData = Tab.Settings,
|
||||
OnClicked = SelectTab
|
||||
};
|
||||
//TODO: translate
|
||||
|
||||
new GUIButton(new RectTransform(new Vector2(1.0f, 1.0f), optionList.RectTransform), TextManager.Get("CreditsButton"), textAlignment: Alignment.Left, style: "MainMenuGUIButton")
|
||||
{
|
||||
ForceUpperCase = true,
|
||||
@@ -323,7 +319,7 @@ namespace Barotrauma
|
||||
StartNewGame = StartGame
|
||||
};
|
||||
|
||||
var hostServerScale = new Vector2(0.7f, 1.0f);
|
||||
var hostServerScale = new Vector2(0.7f, 0.6f);
|
||||
menuTabs[(int)Tab.HostServer] = new GUIFrame(new RectTransform(
|
||||
Vector2.Multiply(relativeSize, hostServerScale), GUI.Canvas, anchor, pivot, minSize.Multiply(hostServerScale), maxSize.Multiply(hostServerScale)) { RelativeOffset = relativeSpacing });
|
||||
|
||||
@@ -703,7 +699,7 @@ namespace Barotrauma
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!int.TryParse(portBox.Text, out int port) || port < 0 || port > 65535)
|
||||
/*if (!int.TryParse(portBox.Text, out int port) || port < 0 || port > 65535)
|
||||
{
|
||||
portBox.Text = NetConfig.DefaultPort.ToString();
|
||||
portBox.Flash();
|
||||
@@ -720,7 +716,7 @@ namespace Barotrauma
|
||||
portBox.Flash();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
GameMain.NetLobbyScreen = new NetLobbyScreen();
|
||||
try
|
||||
@@ -732,16 +728,22 @@ namespace Barotrauma
|
||||
exeName = "DedicatedServer.exe";
|
||||
}
|
||||
|
||||
int ownerKey = Math.Max(CryptoRandom.Instance.Next(), 1);
|
||||
|
||||
string arguments = "-name \"" + name.Replace("\\", "\\\\").Replace("\"", "\\\"") + "\"" +
|
||||
" -port " + port.ToString() +
|
||||
" -queryport " + queryPort.ToString() +
|
||||
" -public " + isPublicBox.Selected.ToString() +
|
||||
" -password \"" + passwordBox.Text.Replace("\\", "\\\\").Replace("\"", "\\\"") + "\"" +
|
||||
" -upnp " + useUpnpBox.Selected +
|
||||
" -maxplayers " + maxPlayersBox.Text +
|
||||
" -ownerkey " + ownerKey.ToString();
|
||||
" -maxplayers " + maxPlayersBox.Text;
|
||||
|
||||
int ownerKey = 0;
|
||||
|
||||
if (Steam.SteamManager.GetSteamID()!=0)
|
||||
{
|
||||
arguments += " -steamid " + Steam.SteamManager.GetSteamID();
|
||||
}
|
||||
else
|
||||
{
|
||||
ownerKey = Math.Max(CryptoRandom.Instance.Next(), 1);
|
||||
arguments += " -ownerkey " + ownerKey;
|
||||
}
|
||||
|
||||
string filename = exeName;
|
||||
#if LINUX || OSX
|
||||
@@ -752,13 +754,15 @@ namespace Barotrauma
|
||||
FileName = filename,
|
||||
Arguments = arguments,
|
||||
#if !DEBUG
|
||||
CreateNoWindow = true,
|
||||
UseShellExecute = false,
|
||||
WindowStyle = ProcessWindowStyle.Hidden
|
||||
#endif
|
||||
};
|
||||
GameMain.ServerChildProcess = Process.Start(processInfo);
|
||||
Thread.Sleep(1000); //wait until the server is ready before connecting
|
||||
|
||||
GameMain.Client = new GameClient(name, "127.0.0.1:" + port.ToString(), name, ownerKey);
|
||||
GameMain.Client = new GameClient(name, System.Net.IPAddress.Loopback.ToString(), Steam.SteamManager.GetSteamID(), name, ownerKey, true);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -798,7 +802,10 @@ namespace Barotrauma
|
||||
#else
|
||||
joinServerButton.Enabled = true;
|
||||
hostServerButton.Enabled = true;
|
||||
steamWorkshopButton.Enabled = true;
|
||||
if (Steam.SteamManager.USE_STEAM)
|
||||
{
|
||||
steamWorkshopButton.Enabled = true;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -976,6 +983,7 @@ namespace Barotrauma
|
||||
OverflowClip = true
|
||||
};
|
||||
|
||||
/* TODO: allow lidgren servers from client?
|
||||
label = new GUITextBlock(new RectTransform(textLabelSize, parent.RectTransform), TextManager.Get("ServerPort"), textAlignment: textAlignment);
|
||||
portBox = new GUITextBox(new RectTransform(textFieldSize, label.RectTransform, Anchor.CenterRight), textAlignment: textAlignment)
|
||||
{
|
||||
@@ -991,7 +999,7 @@ namespace Barotrauma
|
||||
Text = queryPort.ToString(),
|
||||
ToolTip = TextManager.Get("ServerQueryPortToolTip")
|
||||
};
|
||||
}
|
||||
}*/
|
||||
|
||||
var maxPlayersLabel = new GUITextBlock(new RectTransform(textLabelSize, parent.RectTransform), TextManager.Get("MaxPlayers"), textAlignment: textAlignment);
|
||||
var buttonContainer = new GUILayoutGroup(new RectTransform(textFieldSize, maxPlayersLabel.RectTransform, Anchor.CenterRight), isHorizontal: true)
|
||||
@@ -1027,10 +1035,11 @@ namespace Barotrauma
|
||||
ToolTip = TextManager.Get("PublicServerToolTip")
|
||||
};
|
||||
|
||||
/* TODO: remove UPnP altogether?
|
||||
useUpnpBox = new GUITickBox(new RectTransform(tickBoxSize, parent.RectTransform), TextManager.Get("AttemptUPnP"))
|
||||
{
|
||||
ToolTip = TextManager.Get("AttemptUPnPToolTip")
|
||||
};
|
||||
};*/
|
||||
|
||||
new GUIButton(new RectTransform(new Vector2(0.4f, 0.1f), menuTabs[(int)Tab.HostServer].RectTransform, Anchor.BottomRight)
|
||||
{
|
||||
|
||||
@@ -1383,7 +1383,7 @@ namespace Barotrauma
|
||||
OnClicked = (btn, userdata) => { if (GUI.MouseOn == btn || GUI.MouseOn == btn.TextBlock) ClosePlayerFrame(btn, userdata); return true; }
|
||||
};
|
||||
|
||||
Vector2 frameSize = GameMain.Client.HasPermission(ClientPermissions.ManagePermissions) ? new Vector2(.24f, .34f) : new Vector2(.24f, .14f);
|
||||
Vector2 frameSize = GameMain.Client.HasPermission(ClientPermissions.ManagePermissions) ? new Vector2(.24f, .44f) : new Vector2(.24f, .24f);
|
||||
|
||||
var playerFrameInner = new GUIFrame(new RectTransform(frameSize, playerFrame.RectTransform, Anchor.Center));
|
||||
var paddedPlayerFrame = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.85f), playerFrameInner.RectTransform, Anchor.Center))
|
||||
@@ -1530,13 +1530,29 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
var buttonAreaUpper = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.1f), paddedPlayerFrame.RectTransform), isHorizontal: true);
|
||||
var buttonAreaMiddle = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.1f), paddedPlayerFrame.RectTransform), isHorizontal: true);
|
||||
var buttonAreaLower = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.1f), paddedPlayerFrame.RectTransform), isHorizontal: true);
|
||||
|
||||
|
||||
if (selectedClient.SteamID != 0 && Steam.SteamManager.IsInitialized)
|
||||
{
|
||||
var viewSteamProfileButton = new GUIButton(new RectTransform(new Vector2(0.8f, 1.0f), buttonAreaUpper.RectTransform, Anchor.TopCenter),
|
||||
TextManager.Get("ViewSteamProfile"))
|
||||
{
|
||||
UserData = selectedClient
|
||||
};
|
||||
|
||||
viewSteamProfileButton.OnClicked = (bt, userdata) =>
|
||||
{
|
||||
Steam.SteamManager.Instance.Overlay.OpenUrl("https://steamcommunity.com/profiles/" + selectedClient.SteamID.ToString());
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
if (!myClient)
|
||||
{
|
||||
if (GameMain.Client.HasPermission(ClientPermissions.Ban))
|
||||
{
|
||||
var banButton = new GUIButton(new RectTransform(new Vector2(0.3f, 1.0f), buttonAreaUpper.RectTransform),
|
||||
var banButton = new GUIButton(new RectTransform(new Vector2(0.3f, 1.0f), buttonAreaMiddle.RectTransform),
|
||||
TextManager.Get("Ban"))
|
||||
{
|
||||
UserData = selectedClient
|
||||
@@ -1544,7 +1560,7 @@ namespace Barotrauma
|
||||
banButton.OnClicked = (bt, userdata) => { BanPlayer(selectedClient); return true; };
|
||||
banButton.OnClicked += ClosePlayerFrame;
|
||||
|
||||
var rangebanButton = new GUIButton(new RectTransform(new Vector2(0.3f, 1.0f), buttonAreaUpper.RectTransform),
|
||||
var rangebanButton = new GUIButton(new RectTransform(new Vector2(0.3f, 1.0f), buttonAreaMiddle.RectTransform),
|
||||
TextManager.Get("BanRange"))
|
||||
{
|
||||
UserData = selectedClient
|
||||
@@ -1578,7 +1594,7 @@ namespace Barotrauma
|
||||
kickButton.OnClicked += ClosePlayerFrame;
|
||||
}
|
||||
|
||||
new GUITickBox(new RectTransform(new Vector2(0.25f, 1.0f), buttonAreaUpper.RectTransform, Anchor.TopRight),
|
||||
new GUITickBox(new RectTransform(new Vector2(0.25f, 1.0f), buttonAreaMiddle.RectTransform, Anchor.TopRight),
|
||||
TextManager.Get("Mute"))
|
||||
{
|
||||
IgnoreLayoutGroups = true,
|
||||
|
||||
@@ -10,6 +10,7 @@ using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
||||
namespace Barotrauma
|
||||
@@ -45,7 +46,7 @@ namespace Barotrauma
|
||||
private readonly GUITickBox filterEmpty;
|
||||
|
||||
private string sortedBy;
|
||||
|
||||
|
||||
private readonly GUIButton serverPreviewToggleButton;
|
||||
|
||||
//a timer for preventing the client from spamming the refresh button faster than AllowedRefreshInterval
|
||||
@@ -332,7 +333,14 @@ namespace Barotrauma
|
||||
{
|
||||
if (ipBox.UserData is ServerInfo selectedServer)
|
||||
{
|
||||
JoinServer(selectedServer.IP + ":" + selectedServer.Port, selectedServer.ServerName);
|
||||
if (selectedServer.LobbyID == 0)
|
||||
{
|
||||
JoinServer(selectedServer.IP + ":" + selectedServer.Port, selectedServer.ServerName);
|
||||
}
|
||||
else
|
||||
{
|
||||
Steam.SteamManager.JoinLobby(selectedServer.LobbyID, true);
|
||||
}
|
||||
}
|
||||
else if (!string.IsNullOrEmpty(ipBox.Text))
|
||||
{
|
||||
@@ -474,6 +482,15 @@ namespace Barotrauma
|
||||
RefreshServers();
|
||||
}
|
||||
|
||||
public override void Deselect()
|
||||
{
|
||||
base.Deselect();
|
||||
if (SteamManager.IsInitialized && SteamManager.Instance.LobbyList != null)
|
||||
{
|
||||
SteamManager.Instance.LobbyList.OnLobbiesUpdated = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void FilterServers()
|
||||
{
|
||||
serverList.Content.RemoveChild(serverList.Content.FindChild("noresults"));
|
||||
@@ -671,16 +688,24 @@ namespace Barotrauma
|
||||
|
||||
private void AddToServerList(ServerInfo serverInfo)
|
||||
{
|
||||
var serverFrame = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.06f), serverList.Content.RectTransform) { MinSize = new Point(0, 35) },
|
||||
var serverFrame = serverList.Content.FindChild(d => (d.UserData is ServerInfo info) &&
|
||||
(info.LobbyID==serverInfo.LobbyID && info.IP==serverInfo.IP && info.Port==serverInfo.Port));
|
||||
|
||||
if (serverFrame == null)
|
||||
{
|
||||
serverFrame = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.06f), serverList.Content.RectTransform) { MinSize = new Point(0, 35) },
|
||||
style: "InnerFrame", color: Color.White * 0.5f)
|
||||
{
|
||||
UserData = serverInfo
|
||||
};
|
||||
new GUILayoutGroup(new RectTransform(new Vector2(0.98f, 1.0f), serverFrame.RectTransform, Anchor.Center), isHorizontal: true, childAnchor: Anchor.CenterLeft)
|
||||
{
|
||||
Stretch = true,
|
||||
//RelativeSpacing = 0.02f
|
||||
};
|
||||
{
|
||||
UserData = serverInfo
|
||||
};
|
||||
new GUILayoutGroup(new RectTransform(new Vector2(0.98f, 1.0f), serverFrame.RectTransform, Anchor.Center), isHorizontal: true, childAnchor: Anchor.CenterLeft)
|
||||
{
|
||||
Stretch = true,
|
||||
//RelativeSpacing = 0.02f
|
||||
};
|
||||
}
|
||||
serverFrame.UserData = serverInfo;
|
||||
|
||||
UpdateServerInfo(serverInfo);
|
||||
|
||||
SortList(sortedBy, toggle: false);
|
||||
@@ -901,13 +926,17 @@ namespace Barotrauma
|
||||
return true;
|
||||
}
|
||||
|
||||
private IEnumerable<object> ConnectToServer(string ip, string serverName)
|
||||
private IEnumerable<object> ConnectToServer(string endpoint, string serverName)
|
||||
{
|
||||
string serverIP = null;
|
||||
UInt64 serverSteamID = SteamManager.SteamIDStringToUInt64(endpoint);
|
||||
if (serverSteamID == 0) { serverIP = endpoint; }
|
||||
|
||||
#if !DEBUG
|
||||
try
|
||||
{
|
||||
#endif
|
||||
GameMain.Client = new GameClient(clientNameBox.Text, ip, serverName);
|
||||
GameMain.Client = new GameClient(clientNameBox.Text, serverIP, serverSteamID, serverName);
|
||||
#if !DEBUG
|
||||
}
|
||||
catch (Exception e)
|
||||
@@ -961,7 +990,7 @@ namespace Barotrauma
|
||||
|
||||
public void PingServer(ServerInfo serverInfo, int timeOut)
|
||||
{
|
||||
if (serverInfo?.IP == null)
|
||||
if (string.IsNullOrWhiteSpace(serverInfo?.IP))
|
||||
{
|
||||
serverInfo.PingChecked = true;
|
||||
serverInfo.Ping = -1;
|
||||
@@ -969,7 +998,8 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
long rtt = -1;
|
||||
IPAddress address = IPAddress.Parse(serverInfo.IP);
|
||||
IPAddress address = null;
|
||||
IPAddress.TryParse(serverInfo.IP, out address);
|
||||
if (address != null)
|
||||
{
|
||||
//don't attempt to ping if the address is IPv6 and it's not supported
|
||||
|
||||
@@ -159,6 +159,7 @@ namespace Barotrauma
|
||||
OnSelected = (component, userdata) =>
|
||||
{
|
||||
if (GUI.MouseOn is GUIButton || GUI.MouseOn?.Parent is GUIButton) { return false; }
|
||||
if (GUI.MouseOn is GUITickBox || GUI.MouseOn?.Parent is GUITickBox) { return false; }
|
||||
myItemList.Deselect();
|
||||
if (userdata is Facepunch.Steamworks.Workshop.Item item)
|
||||
{
|
||||
@@ -190,16 +191,6 @@ namespace Barotrauma
|
||||
}
|
||||
};
|
||||
|
||||
new GUIButton(new RectTransform(new Vector2(0.5f, 0.05f), leftColumn.RectTransform), TextManager.Get("CreateWorkshopItem"))
|
||||
{
|
||||
OnClicked = (btn, userData) =>
|
||||
{
|
||||
CreateWorkshopItem();
|
||||
ShowCreateItemFrame();
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
createItemFrame = new GUIFrame(new RectTransform(new Vector2(0.58f, 1.0f), tabs[(int)Tab.Publish].RectTransform, Anchor.TopRight), style: "InnerFrame");
|
||||
|
||||
buttonContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.08f), container.RectTransform), childAnchor: Anchor.CenterLeft);
|
||||
@@ -269,7 +260,11 @@ namespace Barotrauma
|
||||
});
|
||||
SteamManager.GetPopularWorkshopItems((items) => { OnItemsReceived(items, topItemList); }, 20);
|
||||
SteamManager.GetPublishedWorkshopItems((items) => { OnItemsReceived(items, publishedItemList); });
|
||||
RefreshMyItemList();
|
||||
}
|
||||
|
||||
private void RefreshMyItemList()
|
||||
{
|
||||
myItemList.ClearChildren();
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.2f), myItemList.Content.RectTransform), TextManager.Get("WorkshopLabelSubmarines"), textAlignment: Alignment.Center, font: GUI.LargeFont)
|
||||
{
|
||||
@@ -278,12 +273,28 @@ namespace Barotrauma
|
||||
foreach (Submarine sub in Submarine.SavedSubmarines)
|
||||
{
|
||||
if (sub.HasTag(SubmarineTag.HideInMenus)) { continue; }
|
||||
//ignore subs that are part of some content package
|
||||
string subPath = Path.GetFullPath(sub.FilePath);
|
||||
if (ContentPackage.List.Any(cp => cp.Files.Any(f => f.Type == ContentType.Submarine && Path.GetFullPath(f.Path) == subPath)))
|
||||
|
||||
//ignore subs that are part of the vanilla content package
|
||||
if (GameMain.VanillaContent != null &&
|
||||
GameMain.VanillaContent.GetFilesOfType(ContentType.Submarine).Any(s => Path.GetFullPath(s) == subPath))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
//ignore subs that are part of a workshop content package
|
||||
if (ContentPackage.List.Any(cp => !string.IsNullOrEmpty(cp.SteamWorkshopUrl) &&
|
||||
cp.Files.Any(f => f.Type == ContentType.Submarine && Path.GetFullPath(f.Path) == subPath)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
//ignore subs that are defined in a content package with more files than just the sub
|
||||
//(these will be listed in the "content packages" section)
|
||||
if (ContentPackage.List.Any(cp => cp.Files.Count > 1 &&
|
||||
cp.Files.Any(f => f.Type == ContentType.Submarine && Path.GetFullPath(f.Path) == subPath)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
CreateMyItemFrame(sub, myItemList);
|
||||
}
|
||||
|
||||
@@ -294,6 +305,8 @@ namespace Barotrauma
|
||||
foreach (ContentPackage contentPackage in ContentPackage.List)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(contentPackage.SteamWorkshopUrl) || contentPackage.HideInWorkshopMenu) { continue; }
|
||||
//don't list content packages that only define one sub (they're visible in the "Submarines" section)
|
||||
if (contentPackage.Files.Count == 1 && contentPackage.Files[0].Type == ContentType.Submarine) { continue; }
|
||||
CreateMyItemFrame(contentPackage, myItemList);
|
||||
}
|
||||
}
|
||||
@@ -459,6 +472,7 @@ namespace Barotrauma
|
||||
OnClicked = (btn, userdata) =>
|
||||
{
|
||||
item.UnSubscribe();
|
||||
subscribedItemList.RemoveChild(subscribedItemList.Content.GetChildByUserData(item));
|
||||
return true;
|
||||
}
|
||||
};
|
||||
@@ -787,34 +801,40 @@ namespace Barotrauma
|
||||
new GUITextBlock(new RectTransform(new Vector2(0.5f, 0.0f), modificationDate.RectTransform, Anchor.CenterRight), item.Modified.ToString("dd.MM.yyyy"), textAlignment: Alignment.TopRight);
|
||||
}
|
||||
|
||||
private void CreateWorkshopItem()
|
||||
/*private void CreateWorkshopItem()
|
||||
{
|
||||
SteamManager.CreateWorkshopItemStaging(new List<ContentFile>(), out itemEditor, out itemContentPackage);
|
||||
}
|
||||
SteamManager.CreateWorkshopItemStaging("ModName", out itemEditor, out itemContentPackage);
|
||||
}*/
|
||||
private void CreateWorkshopItem(Submarine sub)
|
||||
{
|
||||
SteamManager.CreateWorkshopItemStaging(new List<ContentFile>(), out itemEditor, out itemContentPackage);
|
||||
string destinationFolder = Path.Combine("Mods", sub.Name);
|
||||
itemContentPackage = ContentPackage.CreatePackage(sub.Name, Path.Combine(destinationFolder, SteamManager.MetadataFileName), corePackage: false);
|
||||
SteamManager.CreateWorkshopItemStaging(itemContentPackage, out itemEditor);
|
||||
|
||||
string destinationPath = Path.Combine(SteamManager.WorkshopItemStagingFolder, "Submarines", Path.GetFileName(sub.FilePath));
|
||||
try
|
||||
string submarineDir = Path.GetDirectoryName(sub.FilePath);
|
||||
if (submarineDir != Path.GetDirectoryName(destinationFolder))
|
||||
{
|
||||
File.Copy(sub.FilePath, destinationPath);
|
||||
string destinationPath = Path.Combine(destinationFolder, Path.GetFileName(sub.FilePath));
|
||||
if (!File.Exists(destinationPath))
|
||||
{
|
||||
File.Move(sub.FilePath, destinationPath);
|
||||
}
|
||||
sub.FilePath = destinationPath;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
DebugConsole.ThrowError("Failed to copy submarine file \"" + sub.FilePath + "\" to the Workshop item staging folder.", e);
|
||||
return;
|
||||
}
|
||||
|
||||
itemContentPackage.AddFile(Path.Combine("Submarines", Path.GetFileName(sub.FilePath)), ContentType.Submarine);
|
||||
|
||||
itemContentPackage.AddFile(sub.FilePath, ContentType.Submarine);
|
||||
itemContentPackage.Name = sub.Name;
|
||||
itemContentPackage.Save(itemContentPackage.Path);
|
||||
ContentPackage.List.Add(itemContentPackage);
|
||||
GameMain.Config.SelectedContentPackages.Add(itemContentPackage);
|
||||
|
||||
itemEditor.Title = sub.Name;
|
||||
itemEditor.Tags.Add("Submarine");
|
||||
itemEditor.Description = sub.Description;
|
||||
|
||||
if (sub.PreviewImage != null)
|
||||
{
|
||||
string previewImagePath = Path.GetFullPath(Path.Combine(SteamManager.WorkshopItemStagingFolder, SteamManager.PreviewImageName));
|
||||
string previewImagePath = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(itemContentPackage.Path), SteamManager.PreviewImageName));
|
||||
try
|
||||
{
|
||||
using (Stream s = File.Create(previewImagePath))
|
||||
@@ -837,8 +857,13 @@ namespace Barotrauma
|
||||
}
|
||||
private void CreateWorkshopItem(ContentPackage contentPackage)
|
||||
{
|
||||
SteamManager.CreateWorkshopItemStaging(new List<ContentFile>(), out itemEditor, out itemContentPackage);
|
||||
string modDirectory = "";
|
||||
//SteamManager.CreateWorkshopItemStaging(new List<ContentFile>(), out itemEditor, out itemContentPackage);
|
||||
|
||||
itemContentPackage = contentPackage;
|
||||
SteamManager.CreateWorkshopItemStaging(itemContentPackage, out itemEditor);
|
||||
itemEditor.Title = contentPackage.Name;
|
||||
|
||||
/*string modDirectory = "";
|
||||
foreach (ContentFile file in contentPackage.Files)
|
||||
{
|
||||
itemContentPackage.AddFile(file.Path, file.Type);
|
||||
@@ -858,12 +883,8 @@ namespace Barotrauma
|
||||
if (!string.IsNullOrEmpty(modDirectory))
|
||||
{
|
||||
SaveUtil.CopyFolder(Path.Combine("Mods", modDirectory), Path.Combine(SteamManager.WorkshopItemStagingFolder, "Mods", modDirectory), copySubDirs: true);
|
||||
}
|
||||
}*/
|
||||
|
||||
itemContentPackage.CorePackage = contentPackage.CorePackage;
|
||||
itemContentPackage.Name = contentPackage.Name;
|
||||
itemContentPackage.Save(itemContentPackage.Path);
|
||||
itemEditor.Title = contentPackage.Name;
|
||||
}
|
||||
private void CreateWorkshopItem(Facepunch.Steamworks.Workshop.Item item)
|
||||
{
|
||||
@@ -879,8 +900,16 @@ namespace Barotrauma
|
||||
private void ShowCreateItemFrame()
|
||||
{
|
||||
createItemFrame.ClearChildren();
|
||||
|
||||
if (itemEditor == null) { return; }
|
||||
|
||||
if (itemEditor == null) return;
|
||||
if (itemContentPackage == null)
|
||||
{
|
||||
string errorMsg = "Failed to edit workshop item (content package null)\n" + Environment.StackTrace;
|
||||
DebugConsole.ThrowError(errorMsg);
|
||||
GameAnalyticsManager.AddErrorEventOnce("SteamWorkshopScreen.ShowCreateItemFrame:ContentPackageNull", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
||||
return;
|
||||
}
|
||||
|
||||
var createItemContent = new GUILayoutGroup(new RectTransform(new Vector2(0.92f, 0.92f), createItemFrame.RectTransform, Anchor.Center))
|
||||
{
|
||||
@@ -987,7 +1016,7 @@ namespace Barotrauma
|
||||
Barotrauma.OpenFileDialog ofd = new Barotrauma.OpenFileDialog()
|
||||
{
|
||||
Multiselect = true,
|
||||
InitialDirectory = Path.GetFullPath(SteamManager.WorkshopItemStagingFolder),
|
||||
InitialDirectory = Path.GetFullPath(Path.GetDirectoryName(itemContentPackage.Path)),
|
||||
Filter = TextManager.Get("WorkshopItemPreviewImage") + "|*.png",
|
||||
Title = TextManager.Get("WorkshopItemPreviewImageDialogTitle")
|
||||
};
|
||||
@@ -1018,9 +1047,19 @@ namespace Barotrauma
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//if preview image has not been set, but there's a PreviewImage file inside the mod folder, use that by default
|
||||
if (string.IsNullOrEmpty(itemEditor.PreviewImage))
|
||||
{
|
||||
string previewImagePath = Path.Combine(Path.GetDirectoryName(itemContentPackage.Path), SteamManager.PreviewImageName);
|
||||
if (File.Exists(previewImagePath))
|
||||
{
|
||||
itemEditor.PreviewImage = Path.GetFullPath(previewImagePath);
|
||||
}
|
||||
}
|
||||
if (!string.IsNullOrEmpty(itemEditor.PreviewImage))
|
||||
{
|
||||
itemEditor.PreviewImage = Path.GetFullPath(itemEditor.PreviewImage);
|
||||
if (itemPreviewSprites.ContainsKey(itemEditor.PreviewImage))
|
||||
{
|
||||
itemPreviewSprites[itemEditor.PreviewImage].Remove();
|
||||
@@ -1068,7 +1107,7 @@ namespace Barotrauma
|
||||
new GUIButton(new RectTransform(new Vector2(0.3f, 1.0f), fileListTitle.RectTransform, Anchor.CenterRight), TextManager.Get("WorkshopItemShowFolder"))
|
||||
{
|
||||
IgnoreLayoutGroups = true,
|
||||
OnClicked = (btn, userdata) => { System.Diagnostics.Process.Start(Path.GetFullPath(SteamManager.WorkshopItemStagingFolder)); return true; }
|
||||
OnClicked = (btn, userdata) => { System.Diagnostics.Process.Start(Path.GetFullPath(Path.GetDirectoryName(itemContentPackage.Path))); return true; }
|
||||
};
|
||||
createItemFileList = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.35f), createItemContent.RectTransform));
|
||||
RefreshCreateItemFileList();
|
||||
@@ -1077,11 +1116,11 @@ namespace Barotrauma
|
||||
{
|
||||
RelativeSpacing = 0.05f
|
||||
};
|
||||
|
||||
|
||||
new GUIButton(new RectTransform(new Vector2(0.4f, 1.0f), buttonContainer.RectTransform, Anchor.TopRight), TextManager.Get("WorkshopItemRefreshFileList"))
|
||||
{
|
||||
ToolTip = TextManager.Get("WorkshopItemRefreshFileListTooltip"),
|
||||
OnClicked = (btn, userdata) =>
|
||||
OnClicked = (btn, userdata) =>
|
||||
{
|
||||
itemContentPackage = new ContentPackage(itemContentPackage.Path);
|
||||
RefreshCreateItemFileList();
|
||||
@@ -1096,26 +1135,27 @@ namespace Barotrauma
|
||||
{
|
||||
Barotrauma.OpenFileDialog ofd = new Barotrauma.OpenFileDialog()
|
||||
{
|
||||
InitialDirectory = Path.GetFullPath(SteamManager.WorkshopItemStagingFolder),
|
||||
InitialDirectory = Path.GetFullPath(Path.GetDirectoryName(itemContentPackage.Path)),
|
||||
Title = TextManager.Get("workshopitemaddfiles"),
|
||||
Multiselect = true
|
||||
};
|
||||
if (ofd.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
OnAddFilesSelected(ofd.FileNames);
|
||||
RefreshMyItemList();
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
//use a custom prompt if OpenFileDialog fails (Linux/Mac)
|
||||
var msgBox = new GUIMessageBox(TextManager.Get("workshopitemaddfiles"), "", relativeSize: new Vector2(0.4f, 0.2f),
|
||||
buttons: new string[] { TextManager.Get("Cancel"), TextManager.Get("OK") });
|
||||
buttons: new string[] { TextManager.Get("Cancel"), TextManager.Get("OK") });
|
||||
|
||||
var pathBox = new GUITextBox(new RectTransform(new Vector2(1.0f, 0.5f), msgBox.Content.RectTransform, Anchor.Center) { MinSize = new Point(0, 25) });
|
||||
|
||||
msgBox.Buttons[0].OnClicked += msgBox.Close;
|
||||
msgBox.Buttons[1].OnClicked += msgBox.Close;
|
||||
msgBox.Buttons[1].OnClicked += (btn2, userdata2) =>
|
||||
msgBox.Buttons[1].OnClicked += (btn2, userdata2) =>
|
||||
{
|
||||
if (string.IsNullOrEmpty(pathBox?.Text)) { return true; }
|
||||
string[] filePaths = pathBox.Text.Split(',');
|
||||
@@ -1131,6 +1171,7 @@ namespace Barotrauma
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//the item has been already published if it has a non-zero ID -> allow adding a changenote
|
||||
if (itemEditor.Id > 0)
|
||||
{
|
||||
@@ -1181,6 +1222,9 @@ namespace Barotrauma
|
||||
itemEditor = null;
|
||||
SelectTab(Tab.Browse);
|
||||
deleteVerification.Close();
|
||||
createItemFrame.ClearChildren();
|
||||
itemContentPackage.SteamWorkshopUrl = "";
|
||||
itemContentPackage.Save(itemContentPackage.Path);
|
||||
return true;
|
||||
};
|
||||
deleteVerification.Buttons[1].OnClicked = deleteVerification.Close;
|
||||
@@ -1221,7 +1265,7 @@ namespace Barotrauma
|
||||
|
||||
private void OnPreviewImageSelected(GUIImage previewImageElement, string filePath)
|
||||
{
|
||||
string previewImagePath = Path.GetFullPath(Path.Combine(SteamManager.WorkshopItemStagingFolder, SteamManager.PreviewImageName));
|
||||
string previewImagePath = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(itemContentPackage.Path), SteamManager.PreviewImageName));
|
||||
if (new FileInfo(filePath).Length > 1024 * 1024)
|
||||
{
|
||||
new GUIMessageBox(TextManager.Get("Error"), TextManager.Get("WorkshopItemPreviewImageTooLarge"));
|
||||
@@ -1248,33 +1292,36 @@ namespace Barotrauma
|
||||
if (fileNames == null) { return; }
|
||||
for (int i = 0; i < fileNames.Length; i++)
|
||||
{
|
||||
string file = fileNames[i];
|
||||
if (string.IsNullOrEmpty(file)) { continue; }
|
||||
file = file.Trim();
|
||||
if (!File.Exists(file)) { continue; }
|
||||
string file = fileNames[i]?.Trim();
|
||||
if (string.IsNullOrEmpty(file) || !File.Exists(file)) { continue; }
|
||||
|
||||
string filePathRelativeToStagingFolder = UpdaterUtil.GetRelativePath(file, Path.Combine(Environment.CurrentDirectory, SteamManager.WorkshopItemStagingFolder));
|
||||
string filePathRelativeToBaseFolder = UpdaterUtil.GetRelativePath(file, Environment.CurrentDirectory);
|
||||
//file is not inside the staging folder
|
||||
if (filePathRelativeToStagingFolder.StartsWith(".."))
|
||||
string modFolder = Path.GetDirectoryName(itemContentPackage.Path);
|
||||
string filePathRelativeToModFolder = UpdaterUtil.GetRelativePath(file, Path.Combine(Environment.CurrentDirectory, modFolder));
|
||||
string destinationPath = Path.Combine(modFolder, Path.GetFileName(file));
|
||||
|
||||
//file is not inside the mod folder, we need to move it
|
||||
if (filePathRelativeToModFolder.StartsWith("..") ||
|
||||
Path.GetPathRoot(Environment.CurrentDirectory) != Path.GetPathRoot(file))
|
||||
{
|
||||
//submarines can be included in the content package directly
|
||||
string basePath = Path.GetDirectoryName(filePathRelativeToBaseFolder.Replace("..", ""));
|
||||
if (basePath == "Submarines")
|
||||
string tryPath = destinationPath;
|
||||
//add a number to the filename if a file with the same name already exists
|
||||
i = 2;
|
||||
while (File.Exists(destinationPath))
|
||||
{
|
||||
destinationPath = Path.Combine(modFolder, $"{Path.GetFileNameWithoutExtension(file)} ({i}){Path.GetExtension(file)}");
|
||||
i++;
|
||||
}
|
||||
try
|
||||
{
|
||||
string destinationPath = Path.Combine(SteamManager.WorkshopItemStagingFolder, "Submarines", Path.GetFileName(file));
|
||||
File.Copy(file, destinationPath);
|
||||
itemContentPackage.AddFile(filePathRelativeToBaseFolder, ContentType.Submarine);
|
||||
}
|
||||
else
|
||||
catch (Exception e)
|
||||
{
|
||||
itemContentPackage.AddFile(filePathRelativeToBaseFolder, ContentType.None);
|
||||
DebugConsole.ThrowError("Copying the file \""+file+"\" to the mod folder failed.", e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
itemContentPackage.AddFile(filePathRelativeToStagingFolder, ContentType.None);
|
||||
}
|
||||
itemContentPackage.AddFile(destinationPath, ContentType.None);
|
||||
}
|
||||
itemContentPackage.Save(itemContentPackage.Path);
|
||||
RefreshCreateItemFileList();
|
||||
@@ -1289,9 +1336,9 @@ namespace Barotrauma
|
||||
foreach (ContentFile contentFile in itemContentPackage.Files)
|
||||
{
|
||||
bool illegalPath = !ContentPackage.IsModFilePathAllowed(contentFile);
|
||||
string pathInStagingFolder = Path.Combine(SteamManager.WorkshopItemStagingFolder, contentFile.Path);
|
||||
bool fileInStagingFolder = File.Exists(pathInStagingFolder);
|
||||
bool fileExists = illegalPath ? File.Exists(contentFile.Path) : fileInStagingFolder;
|
||||
//string pathInStagingFolder = Path.Combine(SteamManager.WorkshopItemStagingFolder, contentFile.Path);
|
||||
//bool fileInStagingFolder = File.Exists(pathInStagingFolder);
|
||||
bool fileExists = File.Exists(contentFile.Path);
|
||||
|
||||
var fileFrame = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.12f), createItemFileList.Content.RectTransform) { MinSize = new Point(0, 20) },
|
||||
style: "ListBoxElement")
|
||||
@@ -1309,7 +1356,7 @@ namespace Barotrauma
|
||||
{
|
||||
Selected = fileExists && !illegalPath,
|
||||
Enabled = false,
|
||||
ToolTip = TextManager.Get(fileInStagingFolder ? "WorkshopItemFileIncluded" : "WorkshopItemFileNotIncluded")
|
||||
ToolTip = TextManager.Get(illegalPath ? "WorkshopItemFileNotIncluded" : "WorkshopItemFileIncluded")
|
||||
};
|
||||
|
||||
var nameText = new GUITextBlock(new RectTransform(new Vector2(0.6f, 1.0f), content.RectTransform, Anchor.CenterLeft), contentFile.Path, font: GUI.SmallFont)
|
||||
@@ -1352,6 +1399,7 @@ namespace Barotrauma
|
||||
itemContentPackage.RemoveFile(contentFile);
|
||||
itemContentPackage.Save(itemContentPackage.Path);
|
||||
RefreshCreateItemFileList();
|
||||
RefreshMyItemList();
|
||||
return true;
|
||||
}
|
||||
};
|
||||
@@ -1408,8 +1456,8 @@ namespace Barotrauma
|
||||
if (errorMsg == null)
|
||||
{
|
||||
new GUIMessageBox(
|
||||
TextManager.Get("Error"),
|
||||
TextManager.GetWithVariable("WorkshopItemPublishFailed", "[itemname]", TextManager.EnsureUTF8(item.Title)) + item.Error);
|
||||
TextManager.Get("Error"),
|
||||
TextManager.GetWithVariable("WorkshopItemPublishFailed", "[itemname]", TextManager.EnsureUTF8(item.Title)) + " " + item.Error);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1418,6 +1466,7 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
createItemFrame.ClearChildren();
|
||||
RefreshItemLists();
|
||||
SelectTab(Tab.Browse);
|
||||
}
|
||||
|
||||
|
||||
@@ -646,8 +646,8 @@ namespace Barotrauma
|
||||
|
||||
SoundPlayer.OverrideMusicType = "none";
|
||||
SoundPlayer.OverrideMusicDuration = null;
|
||||
GameMain.SoundManager.SetCategoryGainMultiplier("default", 0.0f);
|
||||
GameMain.SoundManager.SetCategoryGainMultiplier("waterambience", 0.0f);
|
||||
GameMain.SoundManager.SetCategoryGainMultiplier("default", 0.0f, 0);
|
||||
GameMain.SoundManager.SetCategoryGainMultiplier("waterambience", 0.0f, 0);
|
||||
|
||||
linkedSubBox.ClearChildren();
|
||||
foreach (Submarine sub in Submarine.SavedSubmarines)
|
||||
@@ -688,8 +688,8 @@ namespace Barotrauma
|
||||
if (WiringMode) SetWiringMode(false);
|
||||
|
||||
SoundPlayer.OverrideMusicType = null;
|
||||
GameMain.SoundManager.SetCategoryGainMultiplier("default", GameMain.Config.SoundVolume);
|
||||
GameMain.SoundManager.SetCategoryGainMultiplier("waterambience", GameMain.Config.SoundVolume);
|
||||
GameMain.SoundManager.SetCategoryGainMultiplier("default", GameMain.Config.SoundVolume, 0);
|
||||
GameMain.SoundManager.SetCategoryGainMultiplier("waterambience", GameMain.Config.SoundVolume, 0);
|
||||
|
||||
if (dummyCharacter != null)
|
||||
{
|
||||
@@ -1000,7 +1000,8 @@ namespace Barotrauma
|
||||
submarineDescriptionCharacterCount = new GUITextBlock(new RectTransform(new Vector2(.5f, 1f), descriptionHeaderGroup.RectTransform), string.Empty, textAlignment: Alignment.TopRight);
|
||||
|
||||
var descriptionContainer = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.25f), leftColumn.RectTransform));
|
||||
descriptionBox = new GUITextBox(new RectTransform(Vector2.One, descriptionContainer.Content.RectTransform, Anchor.Center), font: GUI.SmallFont, wrap: true);
|
||||
descriptionBox = new GUITextBox(new RectTransform(Vector2.One, descriptionContainer.Content.RectTransform, Anchor.Center), font: GUI.SmallFont, wrap: true, textAlignment: Alignment.TopLeft);
|
||||
descriptionBox.Padding = new Vector4(10 * GUI.Scale);
|
||||
|
||||
descriptionBox.OnTextChanged += (textBox, text) =>
|
||||
{
|
||||
@@ -1189,11 +1190,13 @@ namespace Barotrauma
|
||||
var contentPackList = new GUIListBox(new RectTransform(new Vector2(0.5f, 1.0f - contentPackagesLabel.RectTransform.RelativeSize.Y),
|
||||
horizontalArea.RectTransform, Anchor.BottomRight));
|
||||
|
||||
|
||||
List<string> contentPacks = Submarine.MainSub.RequiredContentPackages.ToList();
|
||||
foreach (ContentPackage contentPack in ContentPackage.List)
|
||||
{
|
||||
if (!contentPacks.Contains(contentPack.Name)) contentPacks.Add(contentPack.Name);
|
||||
{
|
||||
//don't show content packages that only define submarine files
|
||||
//(it doesn't make sense to require another sub to be installed to install this one)
|
||||
if (contentPack.Files.All(cp => cp.Type == ContentType.Submarine)) { continue; }
|
||||
if (!contentPacks.Contains(contentPack.Name)) { contentPacks.Add(contentPack.Name); }
|
||||
}
|
||||
|
||||
foreach (string contentPackageName in contentPacks)
|
||||
@@ -2371,11 +2374,7 @@ namespace Barotrauma
|
||||
sub.UpdateTransform();
|
||||
}
|
||||
|
||||
spriteBatch.Begin(SpriteSortMode.BackToFront,
|
||||
BlendState.AlphaBlend,
|
||||
null, null, null, null,
|
||||
cam.Transform);
|
||||
|
||||
spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.AlphaBlend, transformMatrix: cam.Transform);
|
||||
graphics.Clear(new Color(0.051f, 0.149f, 0.271f, 1.0f));
|
||||
if (GameMain.DebugDraw)
|
||||
{
|
||||
@@ -2383,7 +2382,12 @@ namespace Barotrauma
|
||||
GUI.DrawLine(spriteBatch, new Vector2(cam.WorldView.X, -Submarine.MainSub.HiddenSubPosition.Y), new Vector2(cam.WorldView.Right, -Submarine.MainSub.HiddenSubPosition.Y), Color.White * 0.5f, 1.0f, (int)(2.0f / cam.Zoom));
|
||||
}
|
||||
|
||||
Submarine.Draw(spriteBatch, true);
|
||||
Submarine.DrawBack(spriteBatch, editing: true);
|
||||
|
||||
spriteBatch.End();
|
||||
spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.AlphaBlend, transformMatrix: cam.Transform);
|
||||
|
||||
Submarine.DrawFront(spriteBatch, editing: true);
|
||||
|
||||
if (!CharacterMode && !WiringMode && GUI.MouseOn == null)
|
||||
{
|
||||
|
||||
@@ -12,6 +12,9 @@ namespace Barotrauma.Sounds
|
||||
//key = sample rate, value = filter
|
||||
private static Dictionary<int, BiQuad> muffleFilters = new Dictionary<int, BiQuad>();
|
||||
|
||||
private static List<float> playbackAmplitude;
|
||||
private const int AMPLITUDE_SAMPLE_COUNT = 4410; //100ms in a 44100hz file
|
||||
|
||||
public OggSound(SoundManager owner, string filename, bool stream) : base(owner, filename, stream, true)
|
||||
{
|
||||
if (!ToolBox.IsProperFilenameCase(filename))
|
||||
@@ -32,6 +35,18 @@ namespace Barotrauma.Sounds
|
||||
short[] shortBuffer = new short[bufferSize];
|
||||
|
||||
int readSamples = reader.ReadSamples(floatBuffer, 0, bufferSize);
|
||||
|
||||
playbackAmplitude = new List<float>();
|
||||
for (int i=0;i<bufferSize;i+=reader.Channels*AMPLITUDE_SAMPLE_COUNT)
|
||||
{
|
||||
float maxAmplitude = 0.0f;
|
||||
for (int j=i;j<i+reader.Channels*AMPLITUDE_SAMPLE_COUNT;j++)
|
||||
{
|
||||
if (j >= bufferSize) { break; }
|
||||
maxAmplitude = Math.Max(maxAmplitude, Math.Abs(floatBuffer[j]));
|
||||
}
|
||||
playbackAmplitude.Add(maxAmplitude);
|
||||
}
|
||||
|
||||
CastBuffer(floatBuffer, shortBuffer, readSamples);
|
||||
|
||||
@@ -61,6 +76,15 @@ namespace Barotrauma.Sounds
|
||||
}
|
||||
}
|
||||
|
||||
public override float GetAmplitudeAtPlaybackPos(int playbackPos)
|
||||
{
|
||||
if (playbackAmplitude == null || playbackAmplitude.Count == 0) { return 0.0f; }
|
||||
int index = playbackPos / AMPLITUDE_SAMPLE_COUNT;
|
||||
if (index < 0) { return 0.0f; }
|
||||
if (index >= playbackAmplitude.Count) { index = playbackAmplitude.Count - 1; }
|
||||
return playbackAmplitude[index];
|
||||
}
|
||||
|
||||
public override int FillStreamBuffer(int samplePos, short[] buffer)
|
||||
{
|
||||
if (!Stream) throw new Exception("Called FillStreamBuffer on a non-streamed sound!");
|
||||
|
||||
@@ -179,6 +179,8 @@ namespace Barotrauma.Sounds
|
||||
|
||||
public abstract int FillStreamBuffer(int samplePos, short[] buffer);
|
||||
|
||||
public abstract float GetAmplitudeAtPlaybackPos(int playbackPos);
|
||||
|
||||
public virtual void Dispose()
|
||||
{
|
||||
if (disposed) { return; }
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using OpenAL;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
|
||||
namespace Barotrauma.Sounds
|
||||
{
|
||||
@@ -79,7 +80,7 @@ namespace Barotrauma.Sounds
|
||||
|
||||
public class SoundChannel : IDisposable
|
||||
{
|
||||
private const int STREAM_BUFFER_SIZE = 65536;
|
||||
private const int STREAM_BUFFER_SIZE = 8820;
|
||||
private short[] streamShortBuffer;
|
||||
|
||||
private Vector3? position;
|
||||
@@ -282,6 +283,35 @@ namespace Barotrauma.Sounds
|
||||
}
|
||||
}
|
||||
|
||||
private float streamAmplitude;
|
||||
public float CurrentAmplitude
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!IsPlaying) { return 0.0f; }
|
||||
|
||||
uint alSource = Sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex);
|
||||
if (!IsStream)
|
||||
{
|
||||
int playbackPos; Al.GetSourcei(alSource, Al.SampleOffset, out playbackPos);
|
||||
int alError = Al.GetError();
|
||||
if (alError != Al.NoError)
|
||||
{
|
||||
throw new Exception("Failed to get source's playback position: " + Al.GetErrorString(alError));
|
||||
}
|
||||
return Sound.GetAmplitudeAtPlaybackPos(playbackPos);
|
||||
}
|
||||
else
|
||||
{
|
||||
float retVal = -1.0f;
|
||||
Monitor.Enter(mutex);
|
||||
retVal = streamAmplitude;
|
||||
Monitor.Exit(mutex);
|
||||
return retVal;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private string category;
|
||||
public string Category
|
||||
{
|
||||
@@ -311,10 +341,12 @@ namespace Barotrauma.Sounds
|
||||
private set;
|
||||
}
|
||||
private int streamSeekPos;
|
||||
private bool startedPlaying;
|
||||
private int buffersToRequeue;
|
||||
private bool reachedEndSample;
|
||||
private int queueStartIndex;
|
||||
private readonly uint[] streamBuffers;
|
||||
private readonly List<uint> emptyBuffers;
|
||||
private uint[] unqueuedBuffers;
|
||||
private float[] streamBufferAmplitudes;
|
||||
|
||||
private object mutex;
|
||||
|
||||
@@ -346,12 +378,17 @@ namespace Barotrauma.Sounds
|
||||
FilledByNetwork = sound is VoipSound;
|
||||
decayTimer = 0;
|
||||
streamSeekPos = 0; reachedEndSample = false;
|
||||
startedPlaying = true;
|
||||
|
||||
mutex = new object();
|
||||
buffersToRequeue = 4;
|
||||
muffled = muffle;
|
||||
|
||||
lock (mutex)
|
||||
if (IsStream)
|
||||
{
|
||||
mutex = new object();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (mutex != null) { Monitor.Enter(mutex); }
|
||||
if (sound.Owner.CountPlayingInstances(sound) < sound.MaxSimultaneousInstances)
|
||||
{
|
||||
ALSourceIndex = sound.Owner.AssignFreeSourceToChannel(this);
|
||||
@@ -390,7 +427,8 @@ namespace Barotrauma.Sounds
|
||||
}
|
||||
else
|
||||
{
|
||||
Al.Sourcei(sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex), Al.Buffer, (int)sound.ALBuffer);
|
||||
uint alBuffer = sound.Owner.GetCategoryMuffle(category) || muffle ? sound.ALMuffledBuffer : sound.ALBuffer;
|
||||
Al.Sourcei(sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex), Al.Buffer, (int)alBuffer);
|
||||
int alError = Al.GetError();
|
||||
if (alError != Al.NoError)
|
||||
{
|
||||
@@ -407,7 +445,8 @@ namespace Barotrauma.Sounds
|
||||
streamShortBuffer = new short[STREAM_BUFFER_SIZE];
|
||||
|
||||
streamBuffers = new uint[4];
|
||||
emptyBuffers = new List<uint>();
|
||||
unqueuedBuffers = new uint[4];
|
||||
streamBufferAmplitudes = new float[4];
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
Al.GenBuffer(out streamBuffers[i]);
|
||||
@@ -423,18 +462,27 @@ namespace Barotrauma.Sounds
|
||||
throw new Exception("Generated streamBuffer[" + i.ToString() + "] is invalid!");
|
||||
}
|
||||
}
|
||||
|
||||
Sound.Owner.InitStreamThread();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
this.Position = position;
|
||||
this.Gain = gain;
|
||||
this.Looping = false;
|
||||
this.Near = near;
|
||||
this.Far = far;
|
||||
this.Category = category;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (mutex != null) { Monitor.Exit(mutex); }
|
||||
}
|
||||
|
||||
Sound.Owner.Update();
|
||||
}
|
||||
|
||||
public bool FadingOutAndDisposing;
|
||||
@@ -445,8 +493,9 @@ namespace Barotrauma.Sounds
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
lock (mutex)
|
||||
try
|
||||
{
|
||||
if (mutex != null) { Monitor.Enter(mutex); }
|
||||
if (ALSourceIndex >= 0)
|
||||
{
|
||||
Al.SourceStop(Sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex));
|
||||
@@ -467,19 +516,17 @@ namespace Barotrauma.Sounds
|
||||
throw new Exception("Failed to stop streamed source: " + Al.GetErrorString(alError));
|
||||
}
|
||||
|
||||
int buffersToUnqueue = 0;
|
||||
uint[] unqueuedBuffers = null;
|
||||
|
||||
buffersToUnqueue = 0;
|
||||
Al.GetSourcei(alSource, Al.BuffersProcessed, out buffersToUnqueue);
|
||||
int buffersToRequeue = 0;
|
||||
|
||||
buffersToRequeue = 0;
|
||||
Al.GetSourcei(alSource, Al.BuffersProcessed, out buffersToRequeue);
|
||||
alError = Al.GetError();
|
||||
if (alError != Al.NoError)
|
||||
{
|
||||
throw new Exception("Failed to determine processed buffers from streamed source: " + Al.GetErrorString(alError));
|
||||
}
|
||||
|
||||
unqueuedBuffers = new uint[buffersToUnqueue];
|
||||
Al.SourceUnqueueBuffers(alSource, buffersToUnqueue, unqueuedBuffers);
|
||||
|
||||
Al.SourceUnqueueBuffers(alSource, buffersToRequeue, unqueuedBuffers);
|
||||
alError = Al.GetError();
|
||||
if (alError != Al.NoError)
|
||||
{
|
||||
@@ -518,14 +565,19 @@ namespace Barotrauma.Sounds
|
||||
ALSourceIndex = -1;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (mutex != null) { Monitor.Exit(mutex); }
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateStream()
|
||||
{
|
||||
if (!IsStream) throw new Exception("Called UpdateStream on a non-streamed sound channel!");
|
||||
|
||||
lock (mutex)
|
||||
try
|
||||
{
|
||||
Monitor.Enter(mutex);
|
||||
if (!reachedEndSample)
|
||||
{
|
||||
uint alSource = Sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex);
|
||||
@@ -538,48 +590,38 @@ namespace Barotrauma.Sounds
|
||||
{
|
||||
throw new Exception("Failed to determine playing state from streamed source: " + Al.GetErrorString(alError));
|
||||
}
|
||||
|
||||
int buffersToUnqueue = 0;
|
||||
uint[] unqueuedBuffers = null;
|
||||
if (!startedPlaying)
|
||||
{
|
||||
buffersToUnqueue = 0;
|
||||
Al.GetSourcei(alSource, Al.BuffersProcessed, out buffersToUnqueue);
|
||||
alError = Al.GetError();
|
||||
if (alError != Al.NoError)
|
||||
{
|
||||
throw new Exception("Failed to determine processed buffers from streamed source: " + Al.GetErrorString(alError));
|
||||
}
|
||||
|
||||
unqueuedBuffers = new uint[buffersToUnqueue+emptyBuffers.Count];
|
||||
Al.SourceUnqueueBuffers(alSource, buffersToUnqueue, unqueuedBuffers);
|
||||
for (int i = 0; i < emptyBuffers.Count; i++)
|
||||
{
|
||||
unqueuedBuffers[buffersToUnqueue + i] = emptyBuffers[i];
|
||||
}
|
||||
buffersToUnqueue += emptyBuffers.Count;
|
||||
emptyBuffers.Clear();
|
||||
alError = Al.GetError();
|
||||
if (alError != Al.NoError)
|
||||
{
|
||||
throw new Exception("Failed to unqueue buffers from streamed source: " + Al.GetErrorString(alError));
|
||||
}
|
||||
}
|
||||
else
|
||||
int unqueuedBufferCount;
|
||||
Al.GetSourcei(alSource, Al.BuffersProcessed, out unqueuedBufferCount);
|
||||
alError = Al.GetError();
|
||||
if (alError != Al.NoError)
|
||||
{
|
||||
startedPlaying = false;
|
||||
buffersToUnqueue = 4;
|
||||
unqueuedBuffers = new uint[4];
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
unqueuedBuffers[i] = streamBuffers[i];
|
||||
}
|
||||
throw new Exception("Failed to determine processed buffers from streamed source: " + Al.GetErrorString(alError));
|
||||
}
|
||||
|
||||
Al.SourceUnqueueBuffers(alSource, unqueuedBufferCount, unqueuedBuffers);
|
||||
alError = Al.GetError();
|
||||
if (alError != Al.NoError)
|
||||
{
|
||||
throw new Exception("Failed to unqueue buffers from streamed source: " + Al.GetErrorString(alError));
|
||||
}
|
||||
|
||||
for (int i = 0; i < buffersToUnqueue; i++)
|
||||
buffersToRequeue += unqueuedBufferCount;
|
||||
|
||||
int iterCount = buffersToRequeue;
|
||||
for (int k = 0; k < iterCount; k++)
|
||||
{
|
||||
int index = queueStartIndex;
|
||||
short[] buffer = streamShortBuffer;
|
||||
int readSamples = Sound.FillStreamBuffer(streamSeekPos, buffer);
|
||||
float readAmplitude = 0.0f;
|
||||
|
||||
for (int i=0;i<Math.Min(readSamples, buffer.Length);i++)
|
||||
{
|
||||
float sampleF = ((float)buffer[i]) / ((float)short.MaxValue);
|
||||
readAmplitude = Math.Max(readAmplitude, Math.Abs(sampleF));
|
||||
}
|
||||
|
||||
if (FilledByNetwork)
|
||||
{
|
||||
if (Sound is VoipSound voipSound)
|
||||
@@ -589,6 +631,7 @@ namespace Barotrauma.Sounds
|
||||
|
||||
if (readSamples <= 0)
|
||||
{
|
||||
streamAmplitude *= 0.5f;
|
||||
decayTimer++;
|
||||
if (decayTimer > 120) //TODO: replace magic number
|
||||
{
|
||||
@@ -618,38 +661,54 @@ namespace Barotrauma.Sounds
|
||||
|
||||
if (readSamples > 0)
|
||||
{
|
||||
Al.BufferData<short>(unqueuedBuffers[i], Sound.ALFormat, buffer, readSamples, Sound.SampleRate);
|
||||
streamBufferAmplitudes[index] = readAmplitude;
|
||||
|
||||
Al.BufferData<short>(streamBuffers[index], Sound.ALFormat, buffer, readSamples, Sound.SampleRate);
|
||||
|
||||
alError = Al.GetError();
|
||||
if (alError != Al.NoError)
|
||||
{
|
||||
throw new Exception("Failed to assign data to stream buffer: " +
|
||||
Al.GetErrorString(alError) + ": " + unqueuedBuffers[i].ToString() + "/" + unqueuedBuffers.Length + ", readSamples: " + readSamples);
|
||||
Al.GetErrorString(alError) + ": " + streamBuffers[index].ToString() + "/" + streamBuffers.Length + ", readSamples: " + readSamples);
|
||||
}
|
||||
|
||||
Al.SourceQueueBuffer(alSource, unqueuedBuffers[i]);
|
||||
Al.SourceQueueBuffer(alSource, streamBuffers[index]);
|
||||
queueStartIndex = (queueStartIndex + 1) % 4;
|
||||
|
||||
alError = Al.GetError();
|
||||
if (alError != Al.NoError)
|
||||
{
|
||||
throw new Exception("Failed to queue buffer[" + i.ToString() + "] to stream: " + Al.GetErrorString(alError));
|
||||
throw new Exception("Failed to queue streamBuffer[" + index.ToString() + "] to stream: " + Al.GetErrorString(alError));
|
||||
}
|
||||
}
|
||||
else if (readSamples < 0)
|
||||
{
|
||||
reachedEndSample = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
emptyBuffers.Add((uint)unqueuedBuffers[i]);
|
||||
if (readSamples < 0)
|
||||
{
|
||||
reachedEndSample = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
buffersToRequeue--;
|
||||
}
|
||||
|
||||
|
||||
streamAmplitude = streamBufferAmplitudes[queueStartIndex];
|
||||
|
||||
Al.GetSourcei(alSource, Al.SourceState, out state);
|
||||
if (state != Al.Playing)
|
||||
{
|
||||
Al.SourcePlay(alSource);
|
||||
}
|
||||
}
|
||||
|
||||
if (reachedEndSample)
|
||||
{
|
||||
streamAmplitude = 0.0f;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
Monitor.Exit(mutex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,6 +100,47 @@ namespace Barotrauma.Sounds
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public float PlaybackAmplitude
|
||||
{
|
||||
get
|
||||
{
|
||||
float aggregateAmplitude = 0.0f;
|
||||
//NOTE: this is obviously not entirely accurate;
|
||||
//It assumes a linear falloff model, and assumes that audio
|
||||
//is simply added together to produce the final result.
|
||||
//Adjustments may be needed under certain scenarios.
|
||||
for (int i=0;i<2;i++)
|
||||
{
|
||||
foreach (SoundChannel soundChannel in playingChannels[i].Where(ch => ch != null))
|
||||
{
|
||||
float amplitude = soundChannel.CurrentAmplitude;
|
||||
amplitude *= soundChannel.Gain;
|
||||
float dist = Vector3.Distance(ListenerPosition, soundChannel.Position ?? ListenerPosition);
|
||||
if (dist > soundChannel.Near)
|
||||
{
|
||||
amplitude *= 1.0f - Math.Min(1.0f, (dist - soundChannel.Near) / (soundChannel.Far - soundChannel.Near));
|
||||
}
|
||||
aggregateAmplitude += amplitude;
|
||||
}
|
||||
}
|
||||
return aggregateAmplitude;
|
||||
}
|
||||
}
|
||||
|
||||
public float CompressionDynamicRangeGain { get; private set; }
|
||||
|
||||
private float voipAttenuatedGain;
|
||||
private double lastAttenuationTime;
|
||||
public float VoipAttenuatedGain
|
||||
{
|
||||
get { return voipAttenuatedGain; }
|
||||
set
|
||||
{
|
||||
lastAttenuationTime = Timing.TotalTime;
|
||||
voipAttenuatedGain = value;
|
||||
}
|
||||
}
|
||||
|
||||
public int LoadedSoundCount
|
||||
{
|
||||
@@ -110,7 +151,43 @@ namespace Barotrauma.Sounds
|
||||
get { return loadedSounds.Select(s => s.Filename).Distinct().Count(); }
|
||||
}
|
||||
|
||||
private Dictionary<string, Pair<float, bool>> categoryModifiers;
|
||||
private class CategoryModifier
|
||||
{
|
||||
public float[] GainMultipliers;
|
||||
public bool Muffle;
|
||||
|
||||
public CategoryModifier(int gainMultiplierIndex, float gain, bool muffle)
|
||||
{
|
||||
Muffle = muffle;
|
||||
GainMultipliers = new float[gainMultiplierIndex+1];
|
||||
for (int i=0;i<GainMultipliers.Length;i++)
|
||||
{
|
||||
if (i==gainMultiplierIndex)
|
||||
{
|
||||
GainMultipliers[i] = gain;
|
||||
}
|
||||
else
|
||||
{
|
||||
GainMultipliers[i] = 1.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void SetGainMultiplier(int index, float gain)
|
||||
{
|
||||
if (GainMultipliers.Length < index+1)
|
||||
{
|
||||
int oldLength = GainMultipliers.Length;
|
||||
Array.Resize(ref GainMultipliers, index + 1);
|
||||
for (int i=oldLength;i<GainMultipliers.Length;i++)
|
||||
{
|
||||
GainMultipliers[i] = 1.0f;
|
||||
}
|
||||
}
|
||||
GainMultipliers[index] = gain;
|
||||
}
|
||||
}
|
||||
private Dictionary<string, CategoryModifier> categoryModifiers;
|
||||
|
||||
public SoundManager()
|
||||
{
|
||||
@@ -190,6 +267,8 @@ namespace Barotrauma.Sounds
|
||||
ListenerPosition = Vector3.Zero;
|
||||
ListenerTargetVector = new Vector3(0.0f, 0.0f, 1.0f);
|
||||
ListenerUpVector = new Vector3(0.0f, -1.0f, 0.0f);
|
||||
|
||||
CompressionDynamicRangeGain = 1.0f;
|
||||
}
|
||||
|
||||
public Sound LoadSound(string filename, bool stream = false)
|
||||
@@ -257,11 +336,12 @@ namespace Barotrauma.Sounds
|
||||
{
|
||||
if (Disabled) { return -1; }
|
||||
|
||||
lock (playingChannels)
|
||||
//remove a channel that has stopped
|
||||
//or hasn't even been assigned
|
||||
int poolIndex = (int)newChannel.Sound.SourcePoolIndex;
|
||||
|
||||
lock (playingChannels[poolIndex])
|
||||
{
|
||||
//remove a channel that has stopped
|
||||
//or hasn't even been assigned
|
||||
int poolIndex = (int)newChannel.Sound.SourcePoolIndex;
|
||||
for (int i = 0; i < playingChannels[poolIndex].Length; i++)
|
||||
{
|
||||
if (playingChannels[poolIndex][i] == null || !playingChannels[poolIndex][i].IsPlaying)
|
||||
@@ -271,10 +351,10 @@ namespace Barotrauma.Sounds
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
//we couldn't get a free source to assign to this channel!
|
||||
return -1;
|
||||
}
|
||||
|
||||
//we couldn't get a free source to assign to this channel!
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
@@ -291,7 +371,7 @@ namespace Barotrauma.Sounds
|
||||
public bool IsPlaying(Sound sound)
|
||||
{
|
||||
if (Disabled) { return false; }
|
||||
lock (playingChannels)
|
||||
lock (playingChannels[(int)sound.SourcePoolIndex])
|
||||
{
|
||||
for (int i = 0; i < playingChannels[(int)sound.SourcePoolIndex].Length; i++)
|
||||
{
|
||||
@@ -309,7 +389,7 @@ namespace Barotrauma.Sounds
|
||||
{
|
||||
if (Disabled) { return 0; }
|
||||
int count = 0;
|
||||
lock (playingChannels)
|
||||
lock (playingChannels[(int)sound.SourcePoolIndex])
|
||||
{
|
||||
for (int i = 0; i < playingChannels[(int)sound.SourcePoolIndex].Length; i++)
|
||||
{
|
||||
@@ -326,7 +406,7 @@ namespace Barotrauma.Sounds
|
||||
public SoundChannel GetChannelFromSound(Sound sound)
|
||||
{
|
||||
if (Disabled) { return null; }
|
||||
lock (playingChannels)
|
||||
lock (playingChannels[(int)sound.SourcePoolIndex])
|
||||
{
|
||||
for (int i = 0; i < playingChannels[(int)sound.SourcePoolIndex].Length; i++)
|
||||
{
|
||||
@@ -343,7 +423,7 @@ namespace Barotrauma.Sounds
|
||||
public void KillChannels(Sound sound)
|
||||
{
|
||||
if (Disabled) { return; }
|
||||
lock (playingChannels)
|
||||
lock (playingChannels[(int)sound.SourcePoolIndex])
|
||||
{
|
||||
for (int i = 0; i < playingChannels[(int)sound.SourcePoolIndex].Length; i++)
|
||||
{
|
||||
@@ -371,22 +451,23 @@ namespace Barotrauma.Sounds
|
||||
}
|
||||
}
|
||||
|
||||
public void SetCategoryGainMultiplier(string category, float gain)
|
||||
public void SetCategoryGainMultiplier(string category, float gain, int index=0)
|
||||
{
|
||||
if (Disabled) { return; }
|
||||
category = category.ToLower();
|
||||
if (categoryModifiers == null) categoryModifiers = new Dictionary<string, Pair<float, bool>>();
|
||||
if (categoryModifiers == null) categoryModifiers = new Dictionary<string, CategoryModifier>();
|
||||
if (!categoryModifiers.ContainsKey(category))
|
||||
{
|
||||
categoryModifiers.Add(category, new Pair<float, bool>(gain, false));
|
||||
categoryModifiers.Add(category, new CategoryModifier(index, gain, false));
|
||||
}
|
||||
else
|
||||
{
|
||||
categoryModifiers[category].First = gain;
|
||||
categoryModifiers[category].SetGainMultiplier(index, gain);
|
||||
}
|
||||
lock (playingChannels)
|
||||
|
||||
for (int i = 0; i < playingChannels.Length; i++)
|
||||
{
|
||||
for (int i = 0; i < playingChannels.Length; i++)
|
||||
lock (playingChannels[i])
|
||||
{
|
||||
for (int j = 0; j < playingChannels[i].Length; j++)
|
||||
{
|
||||
@@ -399,12 +480,24 @@ namespace Barotrauma.Sounds
|
||||
}
|
||||
}
|
||||
|
||||
public float GetCategoryGainMultiplier(string category)
|
||||
public float GetCategoryGainMultiplier(string category, int index=-1)
|
||||
{
|
||||
if (Disabled) { return 0.0f; }
|
||||
category = category.ToLower();
|
||||
if (categoryModifiers == null || !categoryModifiers.ContainsKey(category)) return 1.0f;
|
||||
return categoryModifiers[category].First;
|
||||
if (index < 0)
|
||||
{
|
||||
float accumulatedMultipliers = 1.0f;
|
||||
for (int i=0;i<categoryModifiers[category].GainMultipliers.Length;i++)
|
||||
{
|
||||
accumulatedMultipliers *= categoryModifiers[category].GainMultipliers[i];
|
||||
}
|
||||
return accumulatedMultipliers;
|
||||
}
|
||||
else
|
||||
{
|
||||
return categoryModifiers[category].GainMultipliers[index];
|
||||
}
|
||||
}
|
||||
|
||||
public void SetCategoryMuffle(string category,bool muffle)
|
||||
@@ -413,23 +506,26 @@ namespace Barotrauma.Sounds
|
||||
|
||||
category = category.ToLower();
|
||||
|
||||
if (categoryModifiers == null) categoryModifiers = new Dictionary<string, Pair<float, bool>>();
|
||||
if (categoryModifiers == null) categoryModifiers = new Dictionary<string, CategoryModifier>();
|
||||
if (!categoryModifiers.ContainsKey(category))
|
||||
{
|
||||
categoryModifiers.Add(category, new Pair<float, bool>(1.0f, muffle));
|
||||
categoryModifiers.Add(category, new CategoryModifier(0, 1.0f, muffle));
|
||||
}
|
||||
else
|
||||
{
|
||||
categoryModifiers[category].Second = muffle;
|
||||
categoryModifiers[category].Muffle = muffle;
|
||||
}
|
||||
|
||||
for (int i = 0; i < playingChannels.Length; i++)
|
||||
{
|
||||
for (int j = 0; j < playingChannels[i].Length; j++)
|
||||
lock (playingChannels[i])
|
||||
{
|
||||
if (playingChannels[i][j] != null && playingChannels[i][j].IsPlaying)
|
||||
for (int j = 0; j < playingChannels[i].Length; j++)
|
||||
{
|
||||
if (playingChannels[i][j].Category.ToLower() == category) playingChannels[i][j].Muffled = muffle;
|
||||
if (playingChannels[i][j] != null && playingChannels[i][j].IsPlaying)
|
||||
{
|
||||
if (playingChannels[i][j].Category.ToLower() == category) playingChannels[i][j].Muffled = muffle;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -441,7 +537,45 @@ namespace Barotrauma.Sounds
|
||||
|
||||
category = category.ToLower();
|
||||
if (categoryModifiers == null || !categoryModifiers.ContainsKey(category)) return false;
|
||||
return categoryModifiers[category].Second;
|
||||
return categoryModifiers[category].Muffle;
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
if (GameMain.Client != null && GameMain.Config.VoipAttenuationEnabled)
|
||||
{
|
||||
if (Timing.TotalTime > lastAttenuationTime+0.2)
|
||||
{
|
||||
voipAttenuatedGain = voipAttenuatedGain * 0.9f + 0.1f;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
voipAttenuatedGain = 1.0f;
|
||||
}
|
||||
SetCategoryGainMultiplier("default", VoipAttenuatedGain, 1);
|
||||
SetCategoryGainMultiplier("ui", VoipAttenuatedGain, 1);
|
||||
SetCategoryGainMultiplier("waterambience", VoipAttenuatedGain, 1);
|
||||
SetCategoryGainMultiplier("music", VoipAttenuatedGain, 1);
|
||||
|
||||
if (GameMain.Config.DynamicRangeCompressionEnabled)
|
||||
{
|
||||
float targetGain = (Math.Min(1.0f, 1.0f / PlaybackAmplitude) - 1.0f) * 0.5f + 1.0f;
|
||||
if (targetGain < CompressionDynamicRangeGain)
|
||||
{
|
||||
//if the target gain is lower than the current gain, lower the current gain immediately to prevent clipping
|
||||
CompressionDynamicRangeGain = targetGain;
|
||||
}
|
||||
else
|
||||
{
|
||||
//otherwise, let it rise back smoothly
|
||||
CompressionDynamicRangeGain = (targetGain) * 0.05f + CompressionDynamicRangeGain * 0.95f;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CompressionDynamicRangeGain = 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
public void InitStreamThread()
|
||||
@@ -464,9 +598,10 @@ namespace Barotrauma.Sounds
|
||||
while (areStreamsPlaying)
|
||||
{
|
||||
areStreamsPlaying = false;
|
||||
lock (playingChannels)
|
||||
|
||||
for (int i = 0; i < playingChannels.Length; i++)
|
||||
{
|
||||
for (int i = 0; i < playingChannels.Length; i++)
|
||||
lock (playingChannels[i])
|
||||
{
|
||||
for (int j = 0; j < playingChannels[i].Length; j++)
|
||||
{
|
||||
@@ -497,14 +632,14 @@ namespace Barotrauma.Sounds
|
||||
Thread.Sleep(10); //TODO: use a separate thread for network audio?
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (Disabled) { return; }
|
||||
|
||||
lock (playingChannels)
|
||||
for (int i = 0; i < playingChannels.Length; i++)
|
||||
{
|
||||
for (int i = 0; i < playingChannels.Length; i++)
|
||||
lock (playingChannels[i])
|
||||
{
|
||||
for (int j = 0; j < playingChannels[i].Length; j++)
|
||||
{
|
||||
@@ -512,6 +647,7 @@ namespace Barotrauma.Sounds
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
streamingThread?.Join();
|
||||
for (int i = loadedSounds.Count - 1; i >= 0; i--)
|
||||
{
|
||||
|
||||
@@ -393,19 +393,19 @@ namespace Barotrauma
|
||||
if (Math.Abs(diff.X) < FireSoundRange && Math.Abs(diff.Y) < FireSoundRange)
|
||||
{
|
||||
Vector2 diffLeft = (fs.WorldPosition + new Vector2(fs.Size.X, fs.Size.Y / 2)) - listenerPos;
|
||||
if (diff.X < fs.Size.X / 2.0f) diff.X = 0.0f;
|
||||
if (Math.Abs(diff.X) < fs.Size.X / 2.0f) { diffLeft.X = 0.0f; }
|
||||
if (diffLeft.X <= 0)
|
||||
{
|
||||
float distFallOffLeft = diffLeft.Length() / FireSoundRange;
|
||||
if (distFallOffLeft < 0.99f)
|
||||
{
|
||||
fireVolumeLeft[0] += (1.0f - distFallOffLeft) * (fs.Size.X / FireSoundLargeLimit);
|
||||
fireVolumeLeft[0] += (1.0f - distFallOffLeft);
|
||||
if (fs.Size.X > FireSoundLargeLimit) fireVolumeLeft[1] += (1.0f - distFallOffLeft) * ((fs.Size.X - FireSoundLargeLimit) / FireSoundLargeLimit);
|
||||
}
|
||||
}
|
||||
|
||||
Vector2 diffRight = (fs.WorldPosition + new Vector2(0.0f, fs.Size.Y / 2)) - listenerPos;
|
||||
if (diff.X < fs.Size.X / 2.0f) diff.X = 0.0f;
|
||||
if (Math.Abs(diff.X) < fs.Size.X / 2.0f) { diffRight.X = 0.0f; }
|
||||
if (diffRight.X >= 0)
|
||||
{
|
||||
float distFallOffRight = diffRight.Length() / FireSoundRange;
|
||||
|
||||
@@ -32,6 +32,11 @@ namespace Barotrauma.Sounds
|
||||
video = vid;
|
||||
}
|
||||
|
||||
public override float GetAmplitudeAtPlaybackPos(int playbackPos)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override bool IsPlaying()
|
||||
{
|
||||
bool retVal = false;
|
||||
@@ -65,8 +70,15 @@ namespace Barotrauma.Sounds
|
||||
SoundChannel chn = null;
|
||||
lock (mutex)
|
||||
{
|
||||
if (soundChannel != null) soundChannel.Dispose();
|
||||
chn = new SoundChannel(this, gain, null, 1.0f, 3.0f, "video", false);
|
||||
if (soundChannel != null)
|
||||
{
|
||||
soundChannel.Dispose();
|
||||
soundChannel = null;
|
||||
}
|
||||
}
|
||||
chn = new SoundChannel(this, gain, null, 1.0f, 3.0f, "video", false);
|
||||
lock (mutex)
|
||||
{
|
||||
soundChannel = chn;
|
||||
}
|
||||
return chn;
|
||||
|
||||
@@ -25,7 +25,7 @@ namespace Barotrauma.Sounds
|
||||
}
|
||||
|
||||
private VoipQueue queue;
|
||||
public int bufferID = 0;
|
||||
private int bufferID = 0;
|
||||
|
||||
private SoundChannel soundChannel;
|
||||
|
||||
@@ -54,6 +54,11 @@ namespace Barotrauma.Sounds
|
||||
}
|
||||
}
|
||||
|
||||
public float CurrentAmplitude
|
||||
{
|
||||
get { return soundChannel?.CurrentAmplitude ?? 0.0f; }
|
||||
}
|
||||
|
||||
public VoipSound(SoundManager owner, VoipQueue q) : base(owner, "voip", true, true)
|
||||
{
|
||||
VoipConfig.SetupEncoding();
|
||||
@@ -70,6 +75,11 @@ namespace Barotrauma.Sounds
|
||||
soundChannel = chn;
|
||||
}
|
||||
|
||||
public override float GetAmplitudeAtPlaybackPos(int playbackPos)
|
||||
{
|
||||
throw new NotImplementedException(); //TODO: implement?
|
||||
}
|
||||
|
||||
public void SetPosition(Vector3? pos)
|
||||
{
|
||||
soundChannel.Position = pos;
|
||||
|
||||
@@ -3,6 +3,7 @@ using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
@@ -75,14 +76,13 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public void ReloadTexture()
|
||||
{
|
||||
var sprites = LoadedSprites.Where(s => s.Texture == texture).ToList();
|
||||
texture.Dispose();
|
||||
texture = null;
|
||||
public void ReloadTexture(bool updateAllSprites = false) => ReloadTexture(updateAllSprites ? LoadedSprites.Where(s => s.Texture == texture) : new Sprite[] { this });
|
||||
|
||||
public void ReloadTexture(IEnumerable<Sprite> spritesToUpdate)
|
||||
{
|
||||
texture.Dispose();
|
||||
texture = TextureLoader.FromFile(FilePath, preMultipliedAlpha);
|
||||
foreach (Sprite sprite in sprites)
|
||||
foreach (Sprite sprite in spritesToUpdate)
|
||||
{
|
||||
sprite.texture = texture;
|
||||
}
|
||||
|
||||
@@ -100,15 +100,19 @@ namespace Barotrauma
|
||||
return Color.Lerp(gradient[(int)scaledT], gradient[(int)Math.Min(scaledT + 1, gradient.Length - 1)], (scaledT - (int)scaledT));
|
||||
}
|
||||
|
||||
public static string WrapText(string text, float lineLength, ScalableFont font, float textScale = 1.0f) //TODO: could integrate this into the ScalableFont class directly
|
||||
public static string WrapText(string text, float lineLength, ScalableFont font, float textScale = 1.0f, bool playerInput = false) //TODO: could integrate this into the ScalableFont class directly
|
||||
{
|
||||
Vector2 textSize = font.MeasureString(text);
|
||||
if (textSize.X < lineLength) { return text; }
|
||||
|
||||
text = text.Replace("\n", " \n ");
|
||||
if (!playerInput)
|
||||
{
|
||||
text = text.Replace("\n", " \n ");
|
||||
}
|
||||
|
||||
List<string> words = new List<string>();
|
||||
string currWord = "";
|
||||
|
||||
for (int i = 0; i < text.Length; i++)
|
||||
{
|
||||
if (TextManager.IsCJK(text[i].ToString()))
|
||||
@@ -127,6 +131,7 @@ namespace Barotrauma
|
||||
words.Add(currWord);
|
||||
currWord = "";
|
||||
}
|
||||
words.Add(string.Empty);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -144,69 +149,128 @@ namespace Barotrauma
|
||||
Vector2 spaceSize = font.MeasureString(" ") * textScale;
|
||||
for (int i = 0; i < words.Count; ++i)
|
||||
{
|
||||
if (words[i].Length == 0)
|
||||
string currentWord = words[i];
|
||||
if (currentWord.Length == 0)
|
||||
{
|
||||
//space
|
||||
// space
|
||||
currentWord = " ";
|
||||
}
|
||||
else if (string.IsNullOrWhiteSpace(words[i]) && words[i] != "\n")
|
||||
else if (string.IsNullOrWhiteSpace(currentWord) && currentWord != "\n")
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Vector2 size = words[i].Length == 0 ? spaceSize : font.MeasureString(words[i]) * textScale;
|
||||
Vector2 size = words[i].Length == 0 ? spaceSize : font.MeasureString(currentWord) * textScale;
|
||||
|
||||
if (size.X > lineLength)
|
||||
{
|
||||
if (linePos == 0.0f)
|
||||
float splitSize = 0.0f;
|
||||
List<string> splitWord = new List<string>() { string.Empty };
|
||||
int k = 0;
|
||||
|
||||
for (int j = 0; j < currentWord.Length; j++)
|
||||
{
|
||||
wrappedText.AppendLine(words[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
do
|
||||
splitWord[k] += currentWord[j];
|
||||
splitSize += (font.MeasureString(currentWord[j].ToString()) * textScale).X;
|
||||
|
||||
if (splitSize + linePos > lineLength)
|
||||
{
|
||||
if (words[i].Length == 0) break;
|
||||
|
||||
wrappedText.Append(words[i][0]);
|
||||
words[i] = words[i].Remove(0, 1);
|
||||
|
||||
linePos += size.X;
|
||||
} while (words[i].Length > 0 && (size = font.MeasureString((words[i][0]).ToString()) * textScale).X + linePos < lineLength);
|
||||
|
||||
wrappedText.Append("\n");
|
||||
linePos = 0.0f;
|
||||
i--;
|
||||
linePos = splitSize = 0.0f;
|
||||
splitWord[k] = splitWord[k].Remove(splitWord[k].Length - 1) + "\n";
|
||||
j--;
|
||||
splitWord.Add(string.Empty);
|
||||
k++;
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (linePos + size.X < lineLength)
|
||||
{
|
||||
wrappedText.Append(words[i]);
|
||||
if (words[i] == "\n")
|
||||
for (int j = 0; j < splitWord.Count; j++)
|
||||
{
|
||||
linePos = 0.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
linePos += size.X + spaceSize.X;
|
||||
wrappedText.Append(splitWord[j]);
|
||||
}
|
||||
|
||||
linePos = splitSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
wrappedText.Append("\n");
|
||||
wrappedText.Append(words[i]);
|
||||
if (linePos + size.X < lineLength)
|
||||
{
|
||||
wrappedText.Append(currentWord);
|
||||
if (currentWord == "\n")
|
||||
{
|
||||
linePos = 0.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
linePos += size.X;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
wrappedText.Append("\n");
|
||||
wrappedText.Append(currentWord);
|
||||
|
||||
linePos = size.X + spaceSize.X;
|
||||
}
|
||||
|
||||
if (i < words.Count - 1 && !TextManager.IsCJK(words[i]) && !TextManager.IsCJK(words[i + 1]))
|
||||
{
|
||||
wrappedText.Append(" ");
|
||||
linePos = size.X;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return wrappedText.ToString().Replace(" \n ", "\n");
|
||||
}
|
||||
if (!playerInput)
|
||||
{
|
||||
return wrappedText.ToString().Replace(" \n ", "\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
return wrappedText.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
public static void ParseConnectCommand(string[] args, out string name, out string endpoint, out UInt64 lobbyId)
|
||||
{
|
||||
name = null; endpoint = null; lobbyId = 0;
|
||||
for (int i = 0; i < args.Length - 1; i++)
|
||||
{
|
||||
if (i < args.Length-2 && args[i].Trim().ToLower().Equals("-connect", StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
int j = i + 2;
|
||||
|
||||
name = "";
|
||||
if (args[i + 1].Trim()[0] == '"')
|
||||
{
|
||||
name = args[i + 1].Trim().Substring(1);
|
||||
if (!(name[name.Length - 1] == '"' && (name.Length < 2 || name[name.Length - 1] != '\\')))
|
||||
{
|
||||
for (; j < args.Length - 1; j++)
|
||||
{
|
||||
name += " " + args[j].Trim();
|
||||
if (name[name.Length - 1] == '"' && (name.Length < 2 || name[name.Length - 1] != '\\'))
|
||||
{
|
||||
name = name.Substring(0, name.Length - 1).Replace("\\\"", "\"");
|
||||
j++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
name = name.Substring(0, name.Length - 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
name = args[i + 1].Trim();
|
||||
}
|
||||
endpoint = args[j].Trim();
|
||||
|
||||
break;
|
||||
}
|
||||
else if (args[i].Trim().ToLower().Equals("+connect_lobby", StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
UInt64.TryParse(args[i + 1].Trim(), out lobbyId);
|
||||
endpoint = null;
|
||||
name = null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user