(a00338777) v0.9.2.1
This commit is contained in:
@@ -14,11 +14,6 @@ namespace Barotrauma
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Use as a minimum or static sight range.
|
||||
/// </summary>
|
||||
public static float StaticSightRange = 3000;
|
||||
|
||||
private float soundRange;
|
||||
private float sightRange;
|
||||
@@ -75,7 +70,7 @@ namespace Barotrauma
|
||||
public bool Enabled = true;
|
||||
|
||||
public float MinSoundRange, MinSightRange;
|
||||
public float MaxSoundRange = float.MaxValue, MaxSightRange = float.MaxValue;
|
||||
public float MaxSoundRange = 100000, MaxSightRange = 100000;
|
||||
|
||||
public TargetType Type { get; private set; }
|
||||
|
||||
@@ -128,8 +123,8 @@ namespace Barotrauma
|
||||
{
|
||||
SightRange = element.GetAttributeFloat("sightrange", 0.0f);
|
||||
SoundRange = element.GetAttributeFloat("soundrange", 0.0f);
|
||||
MinSightRange = element.GetAttributeFloat("minsightrange", SightRange);
|
||||
MinSoundRange = element.GetAttributeFloat("minsoundrange", SoundRange);
|
||||
MinSightRange = element.GetAttributeFloat("minsightrange", 0f);
|
||||
MinSoundRange = element.GetAttributeFloat("minsoundrange", 0f);
|
||||
MaxSightRange = element.GetAttributeFloat("maxsightrange", SightRange);
|
||||
MaxSoundRange = element.GetAttributeFloat("maxsoundrange", SoundRange);
|
||||
FadeOutTime = element.GetAttributeFloat("fadeouttime", FadeOutTime);
|
||||
@@ -142,15 +137,9 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public AITarget(Entity e, float sightRange = -1, float soundRange = 0)
|
||||
public AITarget(Entity e)
|
||||
{
|
||||
Entity = e;
|
||||
if (sightRange < 0)
|
||||
{
|
||||
sightRange = StaticSightRange;
|
||||
}
|
||||
SightRange = sightRange;
|
||||
SoundRange = soundRange;
|
||||
List.Add(this);
|
||||
}
|
||||
|
||||
|
||||
@@ -109,9 +109,9 @@ namespace Barotrauma
|
||||
private Dictionary<AITarget, AITargetMemory> targetMemories;
|
||||
|
||||
//the eyesight of the NPC (0.0 = blind, 1.0 = sees every target within sightRange)
|
||||
private float sight;
|
||||
public float sight;
|
||||
//how far the NPC can hear targets from (0.0 = deaf, 1.0 = hears every target within soundRange)
|
||||
private float hearing;
|
||||
public float hearing;
|
||||
|
||||
private float colliderSize;
|
||||
|
||||
@@ -270,11 +270,14 @@ namespace Barotrauma
|
||||
return null;
|
||||
}
|
||||
|
||||
public override void SelectTarget(AITarget target)
|
||||
public override void SelectTarget(AITarget target) => SelectTarget(target, 100);
|
||||
|
||||
public void SelectTarget(AITarget target, float priority)
|
||||
{
|
||||
SelectedAiTarget = target;
|
||||
selectedTargetMemory = GetTargetMemory(target);
|
||||
targetValue = 100.0f;
|
||||
selectedTargetMemory.Priority = priority;
|
||||
targetValue = priority;
|
||||
}
|
||||
|
||||
public override void Update(float deltaTime)
|
||||
@@ -985,7 +988,7 @@ namespace Barotrauma
|
||||
var aiTarget = wallTarget.Structure.AiTarget;
|
||||
if (aiTarget != null && SelectedAiTarget != aiTarget)
|
||||
{
|
||||
SelectTarget(aiTarget);
|
||||
SelectTarget(aiTarget, GetTargetMemory(SelectedAiTarget).Priority);
|
||||
}
|
||||
}
|
||||
if (SelectedAiTarget.Entity is IDamageable damageTarget)
|
||||
|
||||
@@ -370,7 +370,7 @@ namespace Barotrauma
|
||||
if (item.CurrentHull != hull) { continue; }
|
||||
if (AIObjectiveRepairItems.IsValidTarget(item, Character))
|
||||
{
|
||||
if (item.Repairables.All(r => item.Condition > r.ShowRepairUIThreshold)) { continue; }
|
||||
if (item.Repairables.All(r => item.ConditionPercentage > r.ShowRepairUIThreshold)) { continue; }
|
||||
AddTargets<AIObjectiveRepairItems, Item>(Character, item);
|
||||
if (newOrder == null)
|
||||
{
|
||||
@@ -640,7 +640,7 @@ namespace Barotrauma
|
||||
if (item.CurrentHull != hull) { continue; }
|
||||
if (AIObjectiveRepairItems.IsValidTarget(item, character))
|
||||
{
|
||||
if (item.Repairables.All(r => item.Condition > r.ShowRepairUIThreshold)) { continue; }
|
||||
if (item.Repairables.All(r => item.ConditionPercentage > r.ShowRepairUIThreshold)) { continue; }
|
||||
AddTargets<AIObjectiveRepairItems, Item>(character, item);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,6 +142,9 @@ namespace Barotrauma
|
||||
IsPathDirty = false;
|
||||
}
|
||||
|
||||
public Func<PathNode, bool> startNodeFilter;
|
||||
public Func<PathNode, bool> endNodeFilter;
|
||||
|
||||
protected override Vector2 DoSteeringSeek(Vector2 target, float weight)
|
||||
{
|
||||
bool needsNewPath = currentPath != null && currentPath.Unreachable || Vector2.DistanceSquared(target, currentTarget) > 1;
|
||||
@@ -164,7 +167,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
var newPath = pathFinder.FindPath(pos, target, character.Submarine, "(Character: " + character.Name + ")");
|
||||
var newPath = pathFinder.FindPath(pos, target, character.Submarine, "(Character: " + character.Name + ")", startNodeFilter, endNodeFilter);
|
||||
bool useNewPath = currentPath == null || needsNewPath;
|
||||
if (!useNewPath && currentPath != null && currentPath.CurrentNode != null && newPath.Nodes.Any() && !newPath.Unreachable)
|
||||
{
|
||||
|
||||
@@ -14,7 +14,9 @@ namespace Barotrauma
|
||||
private float waitUntilPathUnreachable;
|
||||
private bool getDivingGearIfNeeded;
|
||||
|
||||
public Func<bool> customCondition;
|
||||
public Func<bool> requiredCondition;
|
||||
public Func<PathNode, bool> startNodeFilter;
|
||||
public Func<PathNode, bool> endNodeFilter;
|
||||
|
||||
public bool followControlledCharacter;
|
||||
public bool mimic;
|
||||
@@ -137,7 +139,12 @@ namespace Barotrauma
|
||||
currTargetSimPos -= diff;
|
||||
}
|
||||
}
|
||||
character.AIController.SteeringManager.SteeringSeek(currTargetSimPos);
|
||||
if (PathSteering != null)
|
||||
{
|
||||
PathSteering.startNodeFilter = startNodeFilter;
|
||||
PathSteering.endNodeFilter = endNodeFilter;
|
||||
}
|
||||
SteeringManager.SteeringSeek(currTargetSimPos);
|
||||
if (SteeringManager != PathSteering)
|
||||
{
|
||||
SteeringManager.SteeringAvoid(deltaTime, lookAheadDistance: 5, weight: 1, heading: VectorExtensions.Forward(character.AnimController.Collider.Rotation));
|
||||
@@ -191,7 +198,7 @@ namespace Barotrauma
|
||||
}
|
||||
else if (closeEnough)
|
||||
{
|
||||
if (customCondition == null || customCondition())
|
||||
if (requiredCondition == null || requiredCondition())
|
||||
{
|
||||
if (Target is Item item)
|
||||
{
|
||||
@@ -218,7 +225,7 @@ namespace Barotrauma
|
||||
|
||||
private void CalculateCloseEnough()
|
||||
{
|
||||
float interactionDistance = Target is Item i ? i.InteractDistance * 0.9f : 0;
|
||||
float interactionDistance = Target is Item i ? i.InteractDistance + Math.Max(i.Rect.Width, i.Rect.Height) / 2 : 0;
|
||||
CloseEnough = Math.Max(interactionDistance, CloseEnough);
|
||||
}
|
||||
|
||||
|
||||
+13
-2
@@ -149,7 +149,14 @@ namespace Barotrauma
|
||||
character?.Speak(TextManager.GetWithVariable("DialogCannotRepair", "[itemname]", Item.Name, true), null, 0.0f, "cannotrepair", 10.0f);
|
||||
}
|
||||
}
|
||||
repairable.CurrentFixer = abandon && repairable.CurrentFixer == character ? null : character;
|
||||
if (abandon)
|
||||
{
|
||||
repairable.StopRepairing(character);
|
||||
}
|
||||
else
|
||||
{
|
||||
repairable.StartRepairing(character, Repairable.FixActions.Repair);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -161,7 +168,11 @@ namespace Barotrauma
|
||||
constructor: () =>
|
||||
{
|
||||
previousCondition = -1;
|
||||
var objective = new AIObjectiveGoTo(Item, character, objectiveManager);
|
||||
var objective = new AIObjectiveGoTo(Item, character, objectiveManager)
|
||||
{
|
||||
// Don't stop in ladders, because we can't interact with other items while holding the ladders.
|
||||
endNodeFilter = node => node.Waypoint.Ladders == null
|
||||
};
|
||||
if (repairTool != null)
|
||||
{
|
||||
objective.CloseEnough = repairTool.Range * 0.75f;
|
||||
|
||||
+1
-1
@@ -43,7 +43,7 @@ namespace Barotrauma
|
||||
if (Character.CharacterList.Any(c => c.CurrentHull == item.CurrentHull && !HumanAIController.IsFriendly(c))) { return false; }
|
||||
if (!Objectives.ContainsKey(item))
|
||||
{
|
||||
if (item.Repairables.All(r => item.Condition > r.ShowRepairUIThreshold)) { return false; }
|
||||
if (item.Repairables.All(r => item.ConditionPercentage > r.ShowRepairUIThreshold)) { return false; }
|
||||
}
|
||||
if (RequireAdequateSkills)
|
||||
{
|
||||
|
||||
@@ -157,12 +157,13 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public SteeringPath FindPath(Vector2 start, Vector2 end, Submarine hostSub = null, string errorMsgStr = null)
|
||||
public SteeringPath FindPath(Vector2 start, Vector2 end, Submarine hostSub = null, string errorMsgStr = null, Func<PathNode, bool> startNodeFilter = null, Func<PathNode, bool> endNodeFilter = null)
|
||||
{
|
||||
float closestDist = 0.0f;
|
||||
PathNode startNode = null;
|
||||
foreach (PathNode node in nodes)
|
||||
{
|
||||
if (startNodeFilter != null && !startNodeFilter(node)) { continue; }
|
||||
Vector2 nodePos = node.Position;
|
||||
if (hostSub != null)
|
||||
{
|
||||
@@ -219,6 +220,7 @@ namespace Barotrauma
|
||||
PathNode endNode = null;
|
||||
foreach (PathNode node in nodes)
|
||||
{
|
||||
if (endNodeFilter != null && !endNodeFilter(node)) { continue; }
|
||||
Vector2 nodePos = node.Position;
|
||||
if (hostSub != null)
|
||||
{
|
||||
|
||||
+2
-2
@@ -96,8 +96,8 @@ namespace Barotrauma
|
||||
public virtual AnimationType AnimationType { get; protected set; }
|
||||
|
||||
public static string GetDefaultFileName(string speciesName, AnimationType animType) => $"{speciesName.CapitaliseFirstInvariant()}{animType.ToString()}";
|
||||
public static string GetDefaultFile(string speciesName, AnimationType animType, ContentPackage contentPackage = null) =>
|
||||
$"{GetFolder(speciesName, contentPackage)}{GetDefaultFileName(speciesName, animType)}.xml";
|
||||
public static string GetDefaultFile(string speciesName, AnimationType animType, ContentPackage contentPackage = null)
|
||||
=> Path.Combine(GetFolder(speciesName, contentPackage), $"{GetDefaultFileName(speciesName, animType)}.xml");
|
||||
|
||||
public static string GetFolder(string speciesName, ContentPackage contentPackage = null)
|
||||
{
|
||||
|
||||
+2
-1
@@ -66,7 +66,8 @@ namespace Barotrauma
|
||||
.Concat(Joints.Select(j => j as RagdollSubParams)));
|
||||
|
||||
public static string GetDefaultFileName(string speciesName) => $"{speciesName.CapitaliseFirstInvariant()}DefaultRagdoll";
|
||||
public static string GetDefaultFile(string speciesName, ContentPackage contentPackage = null) => $"{GetFolder(speciesName, contentPackage)}{GetDefaultFileName(speciesName)}.xml";
|
||||
public static string GetDefaultFile(string speciesName, ContentPackage contentPackage = null)
|
||||
=> Path.Combine(GetFolder(speciesName, contentPackage), $"{GetDefaultFileName(speciesName)}.xml");
|
||||
|
||||
private static readonly object[] dummyParams = new object[]
|
||||
{
|
||||
|
||||
@@ -1324,7 +1324,7 @@ namespace Barotrauma
|
||||
|
||||
private void CheckBodyInRest(float deltaTime)
|
||||
{
|
||||
if (Collider.LinearVelocity.LengthSquared() > 0.01f || character.SelectedBy != null || !character.IsDead)
|
||||
if (InWater || Collider.LinearVelocity.LengthSquared() > 0.01f || character.SelectedBy != null || !character.IsDead)
|
||||
{
|
||||
bodyInRestTimer = 0.0f;
|
||||
foreach (Limb limb in Limbs)
|
||||
@@ -1383,10 +1383,12 @@ namespace Barotrauma
|
||||
private bool CheckValidity(PhysicsBody body)
|
||||
{
|
||||
string errorMsg = null;
|
||||
string bodyName = body.UserData is Limb ? "Limb" : "Collider";
|
||||
string bodyName = body.UserData is Limb limb ?
|
||||
"Limb (" + limb.type + ")" :
|
||||
"Collider";
|
||||
if (!MathUtils.IsValid(body.SimPosition) || Math.Abs(body.SimPosition.X) > 1e10f || Math.Abs(body.SimPosition.Y) > 1e10f)
|
||||
{
|
||||
errorMsg = bodyName+ " position invalid (" + body.SimPosition + ", character: " + character.Name + "), resetting the ragdoll.";
|
||||
errorMsg = bodyName + " position invalid (" + body.SimPosition + ", character: " + character.Name + "), resetting the ragdoll.";
|
||||
}
|
||||
else if (!MathUtils.IsValid(body.LinearVelocity) || Math.Abs(body.LinearVelocity.X) > 1000f || Math.Abs(body.LinearVelocity.Y) > 1000f)
|
||||
{
|
||||
@@ -1426,10 +1428,10 @@ namespace Barotrauma
|
||||
{
|
||||
Collider.SetTransform(Vector2.Zero, 0.0f);
|
||||
}
|
||||
foreach (Limb limb in Limbs)
|
||||
foreach (Limb otherLimb in Limbs)
|
||||
{
|
||||
limb.body.SetTransform(Collider.SimPosition, 0.0f);
|
||||
limb.body.ResetDynamics();
|
||||
otherLimb.body.SetTransform(Collider.SimPosition, 0.0f);
|
||||
otherLimb.body.ResetDynamics();
|
||||
}
|
||||
SetInitialLimbPositions();
|
||||
return false;
|
||||
|
||||
@@ -104,6 +104,9 @@ namespace Barotrauma
|
||||
|
||||
public readonly bool IsHumanoid;
|
||||
|
||||
public bool IsTraitor;
|
||||
public string TraitorCurrentObjective = "";
|
||||
|
||||
//the name of the species (e.q. human)
|
||||
public readonly string SpeciesName;
|
||||
|
||||
@@ -1515,12 +1518,12 @@ namespace Barotrauma
|
||||
bool leftHand = Inventory.IsInLimbSlot(item, InvSlotType.LeftHand);
|
||||
|
||||
bool selected = false;
|
||||
if (rightHand && SelectedItems[0] == null)
|
||||
if (rightHand && (SelectedItems[0] == null || SelectedItems[0] == item))
|
||||
{
|
||||
selectedItems[0] = item;
|
||||
selected = true;
|
||||
}
|
||||
if (leftHand && SelectedItems[1] == null)
|
||||
if (leftHand && (SelectedItems[1] == null || SelectedItems[1] == item))
|
||||
{
|
||||
selectedItems[1] = item;
|
||||
selected = true;
|
||||
@@ -1839,7 +1842,7 @@ namespace Barotrauma
|
||||
{
|
||||
DeselectCharacter();
|
||||
}
|
||||
else if (focusedCharacter != null && IsKeyHit(InputType.Grab) && FocusedCharacter.CanInventoryBeAccessed)
|
||||
else if (focusedCharacter != null && IsKeyHit(InputType.Grab) && FocusedCharacter.CanBeDragged)
|
||||
{
|
||||
SelectCharacter(focusedCharacter);
|
||||
}
|
||||
@@ -1954,6 +1957,10 @@ namespace Barotrauma
|
||||
//disable AI characters that are far away from the sub and the controlled character
|
||||
float distSqr = Vector2.DistanceSquared(Submarine.MainSub.WorldPosition, c.WorldPosition);
|
||||
if (Controlled != null)
|
||||
{
|
||||
distSqr = Math.Min(distSqr, Vector2.DistanceSquared(Controlled.WorldPosition, c.WorldPosition));
|
||||
}
|
||||
else
|
||||
{
|
||||
distSqr = Math.Min(distSqr, Vector2.DistanceSquared(GameMain.GameScreen.Cam.GetPosition(), c.WorldPosition));
|
||||
}
|
||||
@@ -2198,16 +2205,15 @@ namespace Barotrauma
|
||||
private void UpdateSightRange()
|
||||
{
|
||||
if (aiTarget == null) { return; }
|
||||
// TODO: the formula might need some tweaking
|
||||
float range = (float)Math.Sqrt(Mass) * 1000.0f + AnimController.Collider.LinearVelocity.Length() * 500.0f;
|
||||
aiTarget.SightRange = MathHelper.Clamp(range, 0, 15000.0f);
|
||||
float range = (float)Math.Sqrt(Mass) * 250 + AnimController.Collider.LinearVelocity.Length() * 500;
|
||||
aiTarget.SightRange = MathHelper.Clamp(range, 0, 10000);
|
||||
}
|
||||
|
||||
private void UpdateSoundRange()
|
||||
{
|
||||
if (aiTarget == null) { return; }
|
||||
float range = Mass / 5 * AnimController.TargetMovement.Length() * Noise;
|
||||
aiTarget.SoundRange = MathHelper.Clamp(range, 0f, 5000f);
|
||||
float range = ((float)Math.Sqrt(Mass) / 3) * (AnimController.TargetMovement.Length() * 2) * Noise;
|
||||
aiTarget.SoundRange = MathHelper.Clamp(range, 0, 10000);
|
||||
}
|
||||
|
||||
public void SetOrder(Order order, string orderOption, Character orderGiver, bool speak = true)
|
||||
@@ -2598,6 +2604,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (selectedItems[i] != null) selectedItems[i].Drop(this);
|
||||
}
|
||||
SelectedConstruction = null;
|
||||
|
||||
AnimController.ResetPullJoints();
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ namespace Barotrauma
|
||||
/// <summary>
|
||||
/// Probability for the affliction to be applied. Used by attacks.
|
||||
/// </summary>
|
||||
public float ApplyProbability;
|
||||
public float ApplyProbability = 1.0f;
|
||||
|
||||
/// <summary>
|
||||
/// Which character gave this affliction
|
||||
|
||||
+26
-3
@@ -9,6 +9,10 @@ namespace Barotrauma
|
||||
{
|
||||
private float invertControlsCooldown = 60.0f;
|
||||
private float stunCoolDown = 60.0f;
|
||||
private float invertControlsTimer;
|
||||
|
||||
private float invertControlsToggleTimer;
|
||||
|
||||
public AfflictionSpaceHerpes(AfflictionPrefab prefab, float strength) : base(prefab, strength)
|
||||
{
|
||||
}
|
||||
@@ -25,10 +29,29 @@ namespace Barotrauma
|
||||
//invert controls every 126-234 seconds when strength is close to 0
|
||||
//every 56-104 seconds when strength is close to 100
|
||||
invertControlsCooldown = (180.0f - Strength) * Rand.Range(0.7f, 1.3f);
|
||||
var invertControlsAffliction = AfflictionPrefab.List.Find(ap => ap.Identifier == "invertcontrols");
|
||||
float invertControlsDuration = MathHelper.Lerp(10.0f, 60.0f, Strength / 100.0f) * Rand.Range(0.7f, 1.3f);
|
||||
characterHealth.ApplyAffliction(null, new Affliction(invertControlsAffliction, invertControlsDuration));
|
||||
invertControlsTimer = MathHelper.Lerp(10.0f, 60.0f, Strength / 100.0f) * Rand.Range(0.7f, 1.3f);
|
||||
}
|
||||
else if (invertControlsTimer > 0.0f)
|
||||
{
|
||||
//randomly toggle inverted controls on/off every 5 seconds
|
||||
invertControlsToggleTimer -= deltaTime;
|
||||
if (invertControlsToggleTimer <= 0.0f)
|
||||
{
|
||||
invertControlsToggleTimer = 5.0f;
|
||||
if (Rand.Range(0.0f, 1.0f) < 0.5f)
|
||||
{
|
||||
characterHealth.ReduceAffliction(null, "invertcontrols", 100);
|
||||
}
|
||||
else
|
||||
{
|
||||
var invertControlsAffliction = AfflictionPrefab.List.Find(ap => ap.Identifier == "invertcontrols");
|
||||
characterHealth.ApplyAffliction(null, new Affliction(invertControlsAffliction, 5.0f));
|
||||
}
|
||||
}
|
||||
|
||||
invertControlsTimer -= deltaTime;
|
||||
}
|
||||
|
||||
|
||||
if (Strength > 50.0f)
|
||||
{
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
using Lidgren.Network;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
using Barotrauma.Networking;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
@@ -732,14 +732,14 @@ namespace Barotrauma
|
||||
return allAfflictions;
|
||||
}
|
||||
|
||||
public void ServerWrite(NetBuffer msg)
|
||||
public void ServerWrite(IWriteMessage msg)
|
||||
{
|
||||
List<Affliction> activeAfflictions = afflictions.FindAll(a => a.Strength > 0.0f && a.Strength >= a.Prefab.ActivationThreshold);
|
||||
|
||||
msg.Write((byte)activeAfflictions.Count);
|
||||
foreach (Affliction affliction in activeAfflictions)
|
||||
{
|
||||
msg.WriteRangedInteger(0, AfflictionPrefab.List.Count - 1, AfflictionPrefab.List.IndexOf(affliction.Prefab));
|
||||
msg.WriteRangedIntegerDeprecated(0, AfflictionPrefab.List.Count - 1, AfflictionPrefab.List.IndexOf(affliction.Prefab));
|
||||
msg.WriteRangedSingle(
|
||||
MathHelper.Clamp(affliction.Strength, 0.0f, affliction.Prefab.MaxStrength),
|
||||
0.0f, affliction.Prefab.MaxStrength, 8);
|
||||
@@ -758,8 +758,8 @@ namespace Barotrauma
|
||||
msg.Write((byte)limbAfflictions.Count);
|
||||
foreach (var limbAffliction in limbAfflictions)
|
||||
{
|
||||
msg.WriteRangedInteger(0, limbHealths.Count - 1, limbHealths.IndexOf(limbAffliction.First));
|
||||
msg.WriteRangedInteger(0, AfflictionPrefab.List.Count - 1, AfflictionPrefab.List.IndexOf(limbAffliction.Second.Prefab));
|
||||
msg.WriteRangedIntegerDeprecated(0, limbHealths.Count - 1, limbHealths.IndexOf(limbAffliction.First));
|
||||
msg.WriteRangedIntegerDeprecated(0, AfflictionPrefab.List.Count - 1, AfflictionPrefab.List.IndexOf(limbAffliction.Second.Prefab));
|
||||
msg.WriteRangedSingle(
|
||||
MathHelper.Clamp(limbAffliction.Second.Strength, 0.0f, limbAffliction.Second.Prefab.MaxStrength),
|
||||
0.0f, limbAffliction.Second.Prefab.MaxStrength, 8);
|
||||
|
||||
@@ -144,6 +144,15 @@ namespace Barotrauma
|
||||
#if SERVER
|
||||
if (GameMain.Server != null && Entity.Spawner != null)
|
||||
{
|
||||
if (GameMain.Server.EntityEventManager.UniqueEvents.Any(ev => ev.Entity == item))
|
||||
{
|
||||
string errorMsg = $"Error while spawning job items. Item {item.Name} created network events before the spawn event had been created.";
|
||||
DebugConsole.ThrowError(errorMsg);
|
||||
GameAnalyticsManager.AddErrorEventOnce("Job.InitializeJobItem:EventsBeforeSpawning", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
||||
GameMain.Server.EntityEventManager.UniqueEvents.RemoveAll(ev => ev.Entity == item);
|
||||
GameMain.Server.EntityEventManager.Events.RemoveAll(ev => ev.Entity == item);
|
||||
}
|
||||
|
||||
Entity.Spawner.CreateNetworkEvent(item, false);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -36,7 +36,8 @@ namespace Barotrauma
|
||||
Afflictions,
|
||||
Buffs,
|
||||
Tutorials,
|
||||
UIStyle
|
||||
UIStyle,
|
||||
TraitorMissions
|
||||
}
|
||||
|
||||
public class ContentPackage
|
||||
@@ -79,6 +80,7 @@ namespace Barotrauma
|
||||
ContentType.LevelGenerationParameters,
|
||||
ContentType.RandomEvents,
|
||||
ContentType.Missions,
|
||||
ContentType.TraitorMissions,
|
||||
ContentType.BackgroundCreaturePrefabs,
|
||||
ContentType.RuinConfig,
|
||||
ContentType.NPCConversations,
|
||||
@@ -96,7 +98,7 @@ namespace Barotrauma
|
||||
public string Path
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
set;
|
||||
}
|
||||
|
||||
public string SteamWorkshopUrl;
|
||||
@@ -419,7 +421,7 @@ namespace Barotrauma
|
||||
switch (contentFile.Type)
|
||||
{
|
||||
case ContentType.Submarine:
|
||||
return path == "Submarines";
|
||||
return path == "Submarines" || path == "Mods";
|
||||
default:
|
||||
return path == "Mods";
|
||||
}
|
||||
@@ -460,8 +462,9 @@ namespace Barotrauma
|
||||
return Files.Where(f => f.Type == type).Select(f => f.Path);
|
||||
}
|
||||
|
||||
public static void LoadAll(string folder)
|
||||
public static void LoadAll()
|
||||
{
|
||||
string folder = ContentPackage.Folder;
|
||||
if (!Directory.Exists(folder))
|
||||
{
|
||||
try
|
||||
@@ -475,14 +478,23 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
string[] files = Directory.GetFiles(folder, "*.xml");
|
||||
|
||||
List.Clear();
|
||||
|
||||
string[] files = Directory.GetFiles(folder, "*.xml");
|
||||
foreach (string filePath in files)
|
||||
{
|
||||
ContentPackage package = new ContentPackage(filePath);
|
||||
List.Add(package);
|
||||
List.Add(new ContentPackage(filePath));
|
||||
}
|
||||
|
||||
string[] modDirectories = Directory.GetDirectories("Mods");
|
||||
foreach (string modDirectory in modDirectories)
|
||||
{
|
||||
if (System.IO.Path.GetFileName(modDirectory.TrimEnd(System.IO.Path.DirectorySeparatorChar)) == "ExampleMod") { continue; }
|
||||
string modFilePath = System.IO.Path.Combine(modDirectory, Steam.SteamManager.MetadataFileName);
|
||||
if (File.Exists(modFilePath))
|
||||
{
|
||||
List.Add(new ContentPackage(modFilePath));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -505,7 +517,7 @@ namespace Barotrauma
|
||||
|
||||
public class ContentFile
|
||||
{
|
||||
public readonly string Path;
|
||||
public string Path;
|
||||
public ContentType Type;
|
||||
|
||||
public Workshop.Item WorkShopItem;
|
||||
|
||||
@@ -142,6 +142,7 @@ namespace Barotrauma
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
handle.Exception = e;
|
||||
DebugConsole.ThrowError("Coroutine \"" + handle.Name + "\" has thrown an exception", e);
|
||||
}
|
||||
}
|
||||
@@ -182,7 +183,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (handle.Thread.ThreadState.HasFlag(ThreadState.Stopped))
|
||||
{
|
||||
if ((CoroutineStatus)handle.Coroutine.Current == CoroutineStatus.Failure)
|
||||
if (handle.Exception!=null || (CoroutineStatus)handle.Coroutine.Current == CoroutineStatus.Failure)
|
||||
{
|
||||
DebugConsole.ThrowError("Coroutine \"" + handle.Name + "\" has failed");
|
||||
}
|
||||
|
||||
@@ -438,7 +438,7 @@ namespace Barotrauma
|
||||
});
|
||||
}));
|
||||
|
||||
commands.Add(new Command("banip", "banip [ip]: Ban the IP address from the server.", null));
|
||||
commands.Add(new Command("banendpoint|banip", "banendpoint [endpoint]: Ban the IP address/SteamID from the server.", null));
|
||||
|
||||
commands.Add(new Command("teleportcharacter|teleport", "teleport [character name]: Teleport the specified character to the position of the cursor. If the name parameter is omitted, the controlled character will be teleported.", (string[] args) =>
|
||||
{
|
||||
@@ -674,6 +674,11 @@ namespace Barotrauma
|
||||
},null));
|
||||
|
||||
#if DEBUG
|
||||
commands.Add(new Command("crash", "crash: Crashes the game.", (string[] args) =>
|
||||
{
|
||||
throw new Exception("crash command issued");
|
||||
}));
|
||||
|
||||
commands.Add(new Command("teleportsub", "teleportsub [start/end]: Teleport the submarine to the start or end of the level. WARNING: does not take outposts into account, so often leads to physics glitches. Only use for debugging.", (string[] args) =>
|
||||
{
|
||||
if (Submarine.MainSub == null || Level.Loaded == null) return;
|
||||
@@ -960,6 +965,7 @@ namespace Barotrauma
|
||||
}));
|
||||
|
||||
#if DEBUG
|
||||
/*TODO: reimplement
|
||||
commands.Add(new Command("simulatedlatency", "simulatedlatency [minimumlatencyseconds] [randomlatencyseconds]: applies a simulated latency to network messages. Useful for simulating real network conditions when testing the multiplayer locally.", (string[] args) =>
|
||||
{
|
||||
if (args.Count() < 2 || (GameMain.NetworkMember == null)) return;
|
||||
@@ -1029,7 +1035,7 @@ namespace Barotrauma
|
||||
}
|
||||
#endif
|
||||
NewMessage("Set packet duplication to " + (int)(duplicates * 100) + "%.", Color.White);
|
||||
}));
|
||||
}));*/
|
||||
#endif
|
||||
|
||||
//"dummy commands" that only exist so that the server can give clients permissions to use them
|
||||
@@ -1502,8 +1508,9 @@ namespace Barotrauma
|
||||
public static void NewMessage(string msg, Color color, bool isCommand = false)
|
||||
{
|
||||
if (string.IsNullOrEmpty((msg))) return;
|
||||
|
||||
|
||||
var newMsg = new ColoredText(msg, color, isCommand);
|
||||
|
||||
lock (queuedMessages)
|
||||
{
|
||||
queuedMessages.Enqueue(new ColoredText(msg, color, isCommand));
|
||||
|
||||
@@ -36,6 +36,8 @@ namespace Barotrauma
|
||||
private List<ScriptedEventSet> selectedEventSets;
|
||||
|
||||
private EventManagerSettings settings;
|
||||
|
||||
private readonly bool isClient;
|
||||
|
||||
public float CurrentIntensity
|
||||
{
|
||||
@@ -51,13 +53,15 @@ namespace Barotrauma
|
||||
{
|
||||
events = new List<ScriptedEvent>();
|
||||
selectedEventSets = new List<ScriptedEventSet>();
|
||||
|
||||
isClient = GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient;
|
||||
}
|
||||
|
||||
public bool Enabled = true;
|
||||
|
||||
public void StartRound(Level level)
|
||||
{
|
||||
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient) return;
|
||||
if (isClient) { return; }
|
||||
|
||||
var suitableSettings = EventManagerSettings.List.FindAll(s =>
|
||||
level.Difficulty >= s.MinLevelDifficulty &&
|
||||
@@ -193,13 +197,13 @@ namespace Barotrauma
|
||||
|
||||
public void Update(float deltaTime)
|
||||
{
|
||||
if (!Enabled) return;
|
||||
if (!Enabled) { return; }
|
||||
|
||||
//clients only calculate the intensity but don't create any events
|
||||
//(the intensity is used for controlling the background music)
|
||||
CalculateCurrentIntensity(deltaTime);
|
||||
|
||||
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient) return;
|
||||
|
||||
if (isClient) { return; }
|
||||
|
||||
roundDuration += deltaTime;
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ namespace Barotrauma
|
||||
private set { failureMessage = value; }
|
||||
}
|
||||
|
||||
private string description;
|
||||
protected string description;
|
||||
public virtual string Description
|
||||
{
|
||||
get { return description; }
|
||||
@@ -155,6 +155,13 @@ namespace Barotrauma
|
||||
return false;
|
||||
}
|
||||
|
||||
protected void ShowMessage(int index)
|
||||
{
|
||||
ShowMessageProjSpecific(index);
|
||||
}
|
||||
|
||||
partial void ShowMessageProjSpecific(int index);
|
||||
|
||||
/// <summary>
|
||||
/// End the mission and give a reward if it was completed successfully
|
||||
/// </summary>
|
||||
|
||||
@@ -5,7 +5,7 @@ using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
enum MissionType
|
||||
public enum MissionType
|
||||
{
|
||||
Random,
|
||||
None,
|
||||
|
||||
@@ -28,6 +28,9 @@ namespace Barotrauma
|
||||
{
|
||||
monsterFile = prefab.ConfigElement.GetAttributeString("monsterfile", "");
|
||||
monsterCount = prefab.ConfigElement.GetAttributeInt("monstercount", 1);
|
||||
|
||||
description = description.Replace("[monster]",
|
||||
TextManager.Get("character." + System.IO.Path.GetFileNameWithoutExtension(monsterFile)));
|
||||
}
|
||||
|
||||
public override void Start(Level level)
|
||||
@@ -66,9 +69,9 @@ namespace Barotrauma
|
||||
|
||||
|
||||
if (activeMonsters.Any()) { return; }
|
||||
#if CLIENT
|
||||
|
||||
ShowMessage(state);
|
||||
#endif
|
||||
|
||||
state = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -94,16 +94,15 @@ namespace Barotrauma
|
||||
if (item.ParentInventory != null) item.body.FarseerBody.IsKinematic = false;
|
||||
if (item.CurrentHull?.Submarine == null) return;
|
||||
|
||||
#if CLIENT
|
||||
ShowMessage(state);
|
||||
#endif
|
||||
|
||||
state = 1;
|
||||
break;
|
||||
case 1:
|
||||
if (!Submarine.MainSub.AtEndPosition && !Submarine.MainSub.AtStartPosition) return;
|
||||
#if CLIENT
|
||||
|
||||
ShowMessage(state);
|
||||
#endif
|
||||
|
||||
state = 2;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
abstract class CampaignMode : GameMode
|
||||
abstract partial class CampaignMode : GameMode
|
||||
{
|
||||
public readonly CargoManager CargoManager;
|
||||
|
||||
@@ -111,9 +111,8 @@ namespace Barotrauma
|
||||
base.Update(deltaTime);
|
||||
|
||||
if (!IsRunning) { return; }
|
||||
#if CLIENT
|
||||
if (GameMain.Client != null) { return; }
|
||||
#endif
|
||||
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient) { return; }
|
||||
|
||||
if (!watchmenSpawned)
|
||||
{
|
||||
if (Level.Loaded.StartOutpost != null) { startWatchman = SpawnWatchman(Level.Loaded.StartOutpost); }
|
||||
@@ -128,7 +127,7 @@ namespace Barotrauma
|
||||
foreach (Character character in Character.CharacterList)
|
||||
{
|
||||
#if SERVER
|
||||
if (string.IsNullOrEmpty(character.OwnerClientIP)) { continue; }
|
||||
if (string.IsNullOrEmpty(character.OwnerClientEndPoint)) { continue; }
|
||||
#else
|
||||
if (!CrewManager.GetCharacters().Contains(character)) { continue; }
|
||||
#endif
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace Barotrauma
|
||||
|
||||
public readonly string Name;
|
||||
|
||||
public string ClientIP
|
||||
public string ClientEndPoint
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
@@ -42,7 +42,7 @@ namespace Barotrauma
|
||||
public CharacterCampaignData(XElement element)
|
||||
{
|
||||
Name = element.GetAttributeString("name", "Unnamed");
|
||||
ClientIP = element.GetAttributeString("ip", "");
|
||||
ClientEndPoint = element.GetAttributeString("endpoint", null) ?? element.GetAttributeString("ip", "");
|
||||
string steamID = element.GetAttributeString("steamid", "");
|
||||
if (!string.IsNullOrEmpty(steamID))
|
||||
{
|
||||
@@ -69,7 +69,7 @@ namespace Barotrauma
|
||||
{
|
||||
XElement element = new XElement("CharacterCampaignData",
|
||||
new XAttribute("name", Name),
|
||||
new XAttribute("ip", ClientIP),
|
||||
new XAttribute("endpoint", ClientEndPoint),
|
||||
new XAttribute("steamid", SteamID));
|
||||
|
||||
CharacterInfo?.Save(element);
|
||||
|
||||
@@ -64,7 +64,7 @@ namespace Barotrauma
|
||||
isRunning = true;
|
||||
}
|
||||
|
||||
public virtual void MsgBox() { }
|
||||
public virtual void ShowStartMessage() { }
|
||||
|
||||
public virtual void AddToGUIUpdateList()
|
||||
{
|
||||
|
||||
@@ -3,7 +3,6 @@ using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
using Lidgren.Network;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
@@ -98,14 +97,11 @@ namespace Barotrauma
|
||||
|
||||
GameMain.GameSession.EndRound("");
|
||||
|
||||
//client character has spawned this round -> remove old data (and replace with an up-to-date one if the client still has an alive character)
|
||||
characterData.RemoveAll(cd => cd.HasSpawned);
|
||||
|
||||
foreach (Client c in GameMain.Server.ConnectedClients)
|
||||
{
|
||||
if (c.HasSpawned)
|
||||
{
|
||||
//client has spawned this round -> remove old data (and replace with new one if the client still has an alive character)
|
||||
characterData.RemoveAll(cd => cd.MatchesClient(c));
|
||||
}
|
||||
|
||||
if (c.Character?.Info != null && !c.Character.IsDead)
|
||||
{
|
||||
characterData.Add(new CharacterCampaignData(c));
|
||||
|
||||
@@ -260,7 +260,7 @@ namespace Barotrauma
|
||||
|
||||
if (GameMode != null)
|
||||
{
|
||||
GameMode.MsgBox();
|
||||
GameMode.ShowStartMessage();
|
||||
|
||||
if (GameMode is MultiPlayerCampaign mpCampaign && GameMain.NetworkMember != null && GameMain.NetworkMember.IsServer)
|
||||
{
|
||||
|
||||
@@ -46,6 +46,8 @@ namespace Barotrauma
|
||||
|
||||
public bool PauseOnFocusLost { get; set; }
|
||||
public bool MuteOnFocusLost { get; set; }
|
||||
public bool DynamicRangeCompressionEnabled { get; set; }
|
||||
public bool VoipAttenuationEnabled { get; set; }
|
||||
public bool UseDirectionalVoiceChat { get; set; }
|
||||
|
||||
public enum VoiceMode
|
||||
@@ -176,9 +178,9 @@ namespace Barotrauma
|
||||
#if CLIENT
|
||||
if (GameMain.SoundManager != null)
|
||||
{
|
||||
GameMain.SoundManager.SetCategoryGainMultiplier("default", soundVolume);
|
||||
GameMain.SoundManager.SetCategoryGainMultiplier("ui", soundVolume);
|
||||
GameMain.SoundManager.SetCategoryGainMultiplier("waterambience", soundVolume);
|
||||
GameMain.SoundManager.SetCategoryGainMultiplier("default", soundVolume, 0);
|
||||
GameMain.SoundManager.SetCategoryGainMultiplier("ui", soundVolume, 0);
|
||||
GameMain.SoundManager.SetCategoryGainMultiplier("waterambience", soundVolume, 0);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -191,7 +193,7 @@ namespace Barotrauma
|
||||
{
|
||||
musicVolume = MathHelper.Clamp(value, 0.0f, 1.0f);
|
||||
#if CLIENT
|
||||
GameMain.SoundManager?.SetCategoryGainMultiplier("music", musicVolume);
|
||||
GameMain.SoundManager?.SetCategoryGainMultiplier("music", musicVolume, 0);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -203,7 +205,7 @@ namespace Barotrauma
|
||||
{
|
||||
voiceChatVolume = MathHelper.Clamp(value, 0.0f, 1.0f);
|
||||
#if CLIENT
|
||||
GameMain.SoundManager?.SetCategoryGainMultiplier("voip", voiceChatVolume * 20.0f);
|
||||
GameMain.SoundManager?.SetCategoryGainMultiplier("voip", voiceChatVolume * 20.0f, 0);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -286,7 +288,7 @@ namespace Barotrauma
|
||||
|
||||
public GameSettings()
|
||||
{
|
||||
ContentPackage.LoadAll(ContentPackage.Folder);
|
||||
ContentPackage.LoadAll();
|
||||
CompletedTutorialNames = new List<string>();
|
||||
|
||||
LoadDefaultConfig();
|
||||
@@ -443,6 +445,11 @@ namespace Barotrauma
|
||||
LoadAudioSettings(doc);
|
||||
LoadControls(doc);
|
||||
LoadContentPackages(doc);
|
||||
|
||||
#if DEBUG
|
||||
WindowMode = WindowMode.Windowed;
|
||||
#endif
|
||||
|
||||
UnsavedSettings = false;
|
||||
}
|
||||
|
||||
@@ -797,6 +804,8 @@ namespace Barotrauma
|
||||
new XAttribute("voicechatvolume", voiceChatVolume),
|
||||
new XAttribute("microphonevolume", microphoneVolume),
|
||||
new XAttribute("muteonfocuslost", MuteOnFocusLost),
|
||||
new XAttribute("dynamicrangecompressionenabled", DynamicRangeCompressionEnabled),
|
||||
new XAttribute("voipattenuationenabled", VoipAttenuationEnabled),
|
||||
new XAttribute("usedirectionalvoicechat", UseDirectionalVoiceChat),
|
||||
new XAttribute("voicesetting", VoiceSetting),
|
||||
new XAttribute("voicecapturedevice", VoiceCaptureDevice ?? ""),
|
||||
@@ -910,7 +919,7 @@ namespace Barotrauma
|
||||
}
|
||||
AutoCheckUpdates = doc.Root.GetAttributeBool("autocheckupdates", AutoCheckUpdates);
|
||||
sendUserStatistics = doc.Root.GetAttributeBool("senduserstatistics", sendUserStatistics);
|
||||
QuickStartSubmarineName = doc.Root.GetAttributeString("quickstartsubmarine", "");
|
||||
QuickStartSubmarineName = doc.Root.GetAttributeString("quickstartsub", QuickStartSubmarineName);
|
||||
useSteamMatchmaking = doc.Root.GetAttributeBool("usesteammatchmaking", useSteamMatchmaking);
|
||||
requireSteamAuthentication = doc.Root.GetAttributeBool("requiresteamauthentication", requireSteamAuthentication);
|
||||
EnableSplashScreen = doc.Root.GetAttributeBool("enablesplashscreen", EnableSplashScreen);
|
||||
@@ -997,8 +1006,11 @@ namespace Barotrauma
|
||||
{
|
||||
SoundVolume = audioSettings.GetAttributeFloat("soundvolume", SoundVolume);
|
||||
MusicVolume = audioSettings.GetAttributeFloat("musicvolume", MusicVolume);
|
||||
DynamicRangeCompressionEnabled = audioSettings.GetAttributeBool("dynamicrangecompressionenabled", DynamicRangeCompressionEnabled);
|
||||
VoipAttenuationEnabled = audioSettings.GetAttributeBool("voipattenuationenabled", VoipAttenuationEnabled);
|
||||
VoiceChatVolume = audioSettings.GetAttributeFloat("voicechatvolume", VoiceChatVolume);
|
||||
MuteOnFocusLost = audioSettings.GetAttributeBool("muteonfocuslost", MuteOnFocusLost);
|
||||
|
||||
UseDirectionalVoiceChat = audioSettings.GetAttributeBool("usedirectionalvoicechat", UseDirectionalVoiceChat);
|
||||
VoiceCaptureDevice = audioSettings.GetAttributeString("voicecapturedevice", VoiceCaptureDevice);
|
||||
NoiseGateThreshold = audioSettings.GetAttributeFloat("noisegatethreshold", NoiseGateThreshold);
|
||||
@@ -1108,6 +1120,8 @@ namespace Barotrauma
|
||||
ChatOpen = true;
|
||||
soundVolume = 0.5f;
|
||||
musicVolume = 0.3f;
|
||||
DynamicRangeCompressionEnabled = true;
|
||||
VoipAttenuationEnabled = true;
|
||||
voiceChatVolume = 0.5f;
|
||||
microphoneVolume = 1.0f;
|
||||
AutoCheckUpdates = true;
|
||||
|
||||
@@ -82,7 +82,7 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public DockingPort(Item item, XElement element)
|
||||
: base(item, element)
|
||||
{
|
||||
@@ -160,7 +160,7 @@ namespace Barotrauma.Items.Components
|
||||
if (DockingTarget != null)
|
||||
{
|
||||
Undock();
|
||||
}
|
||||
}
|
||||
|
||||
if (target.item.Submarine == item.Submarine)
|
||||
{
|
||||
@@ -168,7 +168,7 @@ namespace Barotrauma.Items.Components
|
||||
DockingTarget = null;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
target.InitializeLinks();
|
||||
|
||||
if (!item.linkedTo.Contains(target.item)) item.linkedTo.Add(target.item);
|
||||
@@ -193,7 +193,7 @@ namespace Barotrauma.Items.Components
|
||||
Math.Sign(DockingTarget.item.WorldPosition.X - item.WorldPosition.X) :
|
||||
Math.Sign(DockingTarget.item.WorldPosition.Y - item.WorldPosition.Y);
|
||||
DockingTarget.DockingDir = -DockingDir;
|
||||
|
||||
|
||||
if (door != null && DockingTarget.door != null)
|
||||
{
|
||||
WayPoint myWayPoint = WayPoint.WayPointList.Find(wp => door.LinkedGap == wp.ConnectedGap);
|
||||
@@ -205,7 +205,7 @@ namespace Barotrauma.Items.Components
|
||||
targetWayPoint.linkedTo.Add(myWayPoint);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
CreateJoint(false);
|
||||
|
||||
#if SERVER
|
||||
@@ -246,7 +246,7 @@ namespace Barotrauma.Items.Components
|
||||
else if (DockingTarget.item.Submarine.PhysicsBody.Mass < item.Submarine.PhysicsBody.Mass ||
|
||||
item.Submarine.IsOutpost)
|
||||
{
|
||||
DockingTarget.item.Submarine.SubBody.SetPosition(item.Submarine.SubBody.Position - ConvertUnits.ToDisplayUnits(jointDiff));
|
||||
DockingTarget.item.Submarine.SubBody.SetPosition(DockingTarget.item.Submarine.SubBody.Position - ConvertUnits.ToDisplayUnits(jointDiff));
|
||||
}
|
||||
|
||||
ConnectWireBetweenPorts();
|
||||
@@ -401,7 +401,7 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
|
||||
private void CreateHulls()
|
||||
{
|
||||
{
|
||||
var hullRects = new Rectangle[] { item.WorldRect, DockingTarget.item.WorldRect };
|
||||
var subs = new Submarine[] { item.Submarine, DockingTarget.item.Submarine };
|
||||
|
||||
@@ -416,18 +416,18 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
DockingTarget.CreateDoorBody();
|
||||
}
|
||||
|
||||
|
||||
if (IsHorizontal)
|
||||
{
|
||||
if (hullRects[0].Center.X > hullRects[1].Center.X)
|
||||
{
|
||||
hullRects = new Rectangle[] { DockingTarget.item.WorldRect, item.WorldRect };
|
||||
subs = new Submarine[] { DockingTarget.item.Submarine,item.Submarine };
|
||||
subs = new Submarine[] { DockingTarget.item.Submarine, item.Submarine };
|
||||
}
|
||||
|
||||
hullRects[0] = new Rectangle(hullRects[0].Center.X, hullRects[0].Y, ((int)DockedDistance / 2), hullRects[0].Height);
|
||||
hullRects[1] = new Rectangle(hullRects[1].Center.X - ((int)DockedDistance / 2), hullRects[1].Y, ((int)DockedDistance / 2), hullRects[1].Height);
|
||||
|
||||
|
||||
//expand hulls if needed, so there's no empty space between the sub's hulls and docking port hulls
|
||||
int leftSubRightSide = int.MinValue, rightSubLeftSide = int.MaxValue;
|
||||
foreach (Hull hull in Hull.hullList)
|
||||
@@ -478,7 +478,7 @@ namespace Barotrauma.Items.Components
|
||||
hullRects[1].Width += rightHullDiff;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
hullRects[i].Location -= MathUtils.ToPoint((subs[i].WorldPosition - subs[i].HiddenSubPosition));
|
||||
@@ -503,7 +503,7 @@ namespace Barotrauma.Items.Components
|
||||
hullRects = new Rectangle[] { DockingTarget.item.WorldRect, item.WorldRect };
|
||||
subs = new Submarine[] { DockingTarget.item.Submarine, item.Submarine };
|
||||
}
|
||||
|
||||
|
||||
hullRects[0] = new Rectangle(hullRects[0].X, hullRects[0].Y + (int)(-hullRects[0].Height + DockedDistance) / 2, hullRects[0].Width, ((int)DockedDistance / 2));
|
||||
hullRects[1] = new Rectangle(hullRects[1].X, hullRects[1].Y - hullRects[1].Height / 2, hullRects[1].Width, ((int)DockedDistance / 2));
|
||||
|
||||
@@ -954,7 +954,7 @@ namespace Barotrauma.Items.Components
|
||||
#endif
|
||||
}
|
||||
|
||||
public void ServerWrite(Lidgren.Network.NetBuffer msg, Client c, object[] extraData = null)
|
||||
public void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
|
||||
{
|
||||
msg.Write(docked);
|
||||
|
||||
@@ -965,7 +965,7 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
public void ClientRead(ServerNetObject type, Lidgren.Network.NetBuffer msg, float sendingTime)
|
||||
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
|
||||
{
|
||||
bool isDocked = msg.ReadBoolean();
|
||||
|
||||
|
||||
@@ -313,8 +313,7 @@ namespace Barotrauma.Items.Components
|
||||
PredictedState = null;
|
||||
}
|
||||
}
|
||||
|
||||
LinkedGap.Open = openState;
|
||||
LinkedGap.Open = isBroken ? 1.0f : openState;
|
||||
}
|
||||
|
||||
if (isClosing)
|
||||
@@ -371,7 +370,7 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
LinkedGap.AutoOrient();
|
||||
}
|
||||
LinkedGap.Open = openState;
|
||||
LinkedGap.Open = isBroken ? 1.0f : openState;
|
||||
LinkedGap.PassAmbientLight = Window != Rectangle.Empty;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using Barotrauma.Networking;
|
||||
using FarseerPhysics;
|
||||
using Lidgren.Network;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System.Collections.Generic;
|
||||
using System.Xml.Linq;
|
||||
@@ -286,14 +285,21 @@ namespace Barotrauma.Items.Components
|
||||
item.SetTransform(rightHand.SimPosition, 0.0f);
|
||||
}
|
||||
|
||||
bool alreadySelected = character.HasEquippedItem(item);
|
||||
if (picker.TrySelectItem(item) || picker.HasEquippedItem(item))
|
||||
bool alreadyEquipped = character.HasEquippedItem(item);
|
||||
bool canSelect = picker.TrySelectItem(item);
|
||||
|
||||
if (canSelect || picker.HasEquippedItem(item))
|
||||
{
|
||||
if (!canSelect)
|
||||
{
|
||||
character.DeselectItem(item);
|
||||
}
|
||||
|
||||
item.body.Enabled = true;
|
||||
IsActive = true;
|
||||
|
||||
#if SERVER
|
||||
if (!alreadySelected) GameServer.Log(character.LogName + " equipped " + item.Name, ServerLog.MessageType.ItemInteraction);
|
||||
if (!alreadyEquipped) GameServer.Log(character.LogName + " equipped " + item.Name, ServerLog.MessageType.ItemInteraction);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -557,7 +563,7 @@ namespace Barotrauma.Items.Components
|
||||
DeattachFromWall();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public override XElement Save(XElement parentElement)
|
||||
{
|
||||
if (!attachable)
|
||||
@@ -581,8 +587,8 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
return saveElement;
|
||||
}
|
||||
|
||||
public override void ServerWrite(NetBuffer msg, Client c, object[] extraData = null)
|
||||
|
||||
public override void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
|
||||
{
|
||||
base.ServerWrite(msg, c, extraData);
|
||||
if (!attachable || body == null) { return; }
|
||||
@@ -592,11 +598,11 @@ namespace Barotrauma.Items.Components
|
||||
msg.Write(body.SimPosition.Y);
|
||||
}
|
||||
|
||||
public override void ClientRead(ServerNetObject type, NetBuffer msg, float sendingTime)
|
||||
public override void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
|
||||
{
|
||||
base.ClientRead(type, msg, sendingTime);
|
||||
bool shouldBeAttached = msg.ReadBoolean();
|
||||
Vector2 simPosition = new Vector2(msg.ReadFloat(), msg.ReadFloat());
|
||||
Vector2 simPosition = new Vector2(msg.ReadSingle(), msg.ReadSingle());
|
||||
|
||||
if (!attachable)
|
||||
{
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Barotrauma.Networking;
|
||||
using Lidgren.Network;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Linq;
|
||||
@@ -116,7 +115,7 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
public void ServerWrite(NetBuffer msg, Client c, object[] extraData = null)
|
||||
public void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
|
||||
{
|
||||
msg.Write(deattachTimer);
|
||||
}
|
||||
|
||||
@@ -56,11 +56,9 @@ namespace Barotrauma.Items.Components
|
||||
public MeleeWeapon(Item item, XElement element)
|
||||
: base(item, element)
|
||||
{
|
||||
//throwForce = ToolBox.GetAttributeFloat(element, "throwforce", 1.0f);
|
||||
|
||||
foreach (XElement subElement in element.Elements())
|
||||
{
|
||||
if (subElement.Name.ToString().ToLowerInvariant() != "attack") continue;
|
||||
if (subElement.Name.ToString().ToLowerInvariant() != "attack") { continue; }
|
||||
attack = new Attack(subElement, item.Name + ", MeleeWeapon");
|
||||
}
|
||||
item.IsShootable = true;
|
||||
@@ -70,23 +68,22 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
public override bool Use(float deltaTime, Character character = null)
|
||||
{
|
||||
if (character == null || reloadTimer > 0.0f) return false;
|
||||
if (Item.RequireAimToUse && !character.IsKeyDown(InputType.Aim) || hitting) return false;
|
||||
if (character == null || reloadTimer > 0.0f) { return false; }
|
||||
if (Item.RequireAimToUse && !character.IsKeyDown(InputType.Aim) || hitting) { return false; }
|
||||
|
||||
//don't allow hitting if the character is already hitting with another weapon
|
||||
for (int i = 0; i < 2; i++ )
|
||||
{
|
||||
if (character.SelectedItems[i] == null || character.SelectedItems[i] == Item) continue;
|
||||
if (character.SelectedItems[i] == null || character.SelectedItems[i] == Item) { continue; }
|
||||
|
||||
var otherWeapon = character.SelectedItems[i].GetComponent<MeleeWeapon>();
|
||||
if (otherWeapon == null) continue;
|
||||
|
||||
if (otherWeapon.hitting) return false;
|
||||
if (otherWeapon == null) { continue; }
|
||||
if (otherWeapon.hitting) { return false; }
|
||||
}
|
||||
|
||||
SetUser(character);
|
||||
|
||||
if (hitPos < MathHelper.PiOver4) return false;
|
||||
if (hitPos < MathHelper.PiOver4) { return false; }
|
||||
|
||||
reloadTimer = reload;
|
||||
|
||||
@@ -94,21 +91,20 @@ namespace Barotrauma.Items.Components
|
||||
item.body.FarseerBody.CollidesWith = Physics.CollisionCharacter | Physics.CollisionWall;
|
||||
item.body.FarseerBody.OnCollision += OnCollision;
|
||||
|
||||
foreach (Limb l in character.AnimController.Limbs)
|
||||
if (!character.AnimController.InWater)
|
||||
{
|
||||
//item.body.FarseerBody.IgnoreCollisionWith(l.body.FarseerBody);
|
||||
|
||||
if (character.AnimController.InWater) continue;
|
||||
if (l.type == LimbType.LeftFoot || l.type == LimbType.LeftThigh || l.type == LimbType.LeftLeg) continue;
|
||||
|
||||
if (l.type == LimbType.Head || l.type == LimbType.Torso)
|
||||
foreach (Limb l in character.AnimController.Limbs)
|
||||
{
|
||||
l.body.ApplyLinearImpulse(new Vector2(character.AnimController.Dir * 7.0f, -4.0f));
|
||||
if (l.type == LimbType.LeftFoot || l.type == LimbType.LeftThigh || l.type == LimbType.LeftLeg) { continue; }
|
||||
if (l.type == LimbType.Head || l.type == LimbType.Torso)
|
||||
{
|
||||
l.body.ApplyLinearImpulse(new Vector2(character.AnimController.Dir * 7.0f, -4.0f));
|
||||
}
|
||||
else
|
||||
{
|
||||
l.body.ApplyLinearImpulse(new Vector2(character.AnimController.Dir * 5.0f, -2.0f));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
l.body.ApplyLinearImpulse(new Vector2(character.AnimController.Dir * 5.0f, -2.0f));
|
||||
}
|
||||
}
|
||||
|
||||
hitting = true;
|
||||
@@ -121,7 +117,6 @@ namespace Barotrauma.Items.Components
|
||||
public override void Drop(Character dropper)
|
||||
{
|
||||
base.Drop(dropper);
|
||||
|
||||
hitting = false;
|
||||
hitPos = 0.0f;
|
||||
}
|
||||
@@ -133,17 +128,17 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
public override void Update(float deltaTime, Camera cam)
|
||||
{
|
||||
if (!item.body.Enabled) return;
|
||||
if (!picker.HasSelectedItem(item)) IsActive = false;
|
||||
if (!item.body.Enabled) { return; }
|
||||
if (!picker.HasSelectedItem(item)) { IsActive = false; }
|
||||
|
||||
reloadTimer -= deltaTime;
|
||||
if (reloadTimer < 0) { reloadTimer = 0; }
|
||||
|
||||
if (!picker.IsKeyDown(InputType.Aim) && !hitting) hitPos = 0.0f;
|
||||
if (!picker.IsKeyDown(InputType.Aim) && !hitting) { hitPos = 0.0f; }
|
||||
|
||||
ApplyStatusEffects(ActionType.OnActive, deltaTime, picker);
|
||||
|
||||
if (item.body.Dir != picker.AnimController.Dir) Flip();
|
||||
if (item.body.Dir != picker.AnimController.Dir) { Flip(); }
|
||||
|
||||
AnimController ac = picker.AnimController;
|
||||
|
||||
@@ -236,16 +231,16 @@ namespace Barotrauma.Items.Components
|
||||
if (f2.Body.UserData is Limb)
|
||||
{
|
||||
targetLimb = (Limb)f2.Body.UserData;
|
||||
if (targetLimb.IsSevered || targetLimb.character == null) return false;
|
||||
if (targetLimb.IsSevered || targetLimb.character == null) { return false; }
|
||||
targetCharacter = targetLimb.character;
|
||||
if (targetCharacter == picker) return false;
|
||||
if (targetCharacter == picker){ return false; }
|
||||
if (AllowHitMultiple)
|
||||
{
|
||||
if (hitTargets.Contains(targetCharacter)) return false;
|
||||
if (hitTargets.Contains(targetCharacter)) { return false; }
|
||||
}
|
||||
else
|
||||
{
|
||||
if (hitTargets.Any(t => t is Character)) return false;
|
||||
if (hitTargets.Any(t => t is Character)) { return false; }
|
||||
}
|
||||
hitTargets.Add(targetCharacter);
|
||||
}
|
||||
@@ -256,11 +251,11 @@ namespace Barotrauma.Items.Components
|
||||
targetLimb = targetCharacter.AnimController.GetLimb(LimbType.Torso); //Otherwise armor can be bypassed in strange ways
|
||||
if (AllowHitMultiple)
|
||||
{
|
||||
if (hitTargets.Contains(targetCharacter)) return false;
|
||||
if (hitTargets.Contains(targetCharacter)) { return false; }
|
||||
}
|
||||
else
|
||||
{
|
||||
if (hitTargets.Any(t => t is Character)) return false;
|
||||
if (hitTargets.Any(t => t is Character)) { return false; }
|
||||
}
|
||||
hitTargets.Add(targetCharacter);
|
||||
}
|
||||
@@ -269,11 +264,11 @@ namespace Barotrauma.Items.Components
|
||||
targetStructure = (Structure)f2.Body.UserData;
|
||||
if (AllowHitMultiple)
|
||||
{
|
||||
if (hitTargets.Contains(targetStructure)) return true;
|
||||
if (hitTargets.Contains(targetStructure)) { return true; }
|
||||
}
|
||||
else
|
||||
{
|
||||
if (hitTargets.Any(t => t is Structure)) return true;
|
||||
if (hitTargets.Any(t => t is Structure)) { return true; }
|
||||
}
|
||||
hitTargets.Add(targetStructure);
|
||||
}
|
||||
@@ -303,8 +298,8 @@ namespace Barotrauma.Items.Components
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient) return true;
|
||||
|
||||
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient) { return true; }
|
||||
|
||||
#if SERVER
|
||||
if (GameMain.Server != null && targetCharacter != null) //TODO: Log structure hits
|
||||
|
||||
@@ -3,7 +3,6 @@ using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Xml.Linq;
|
||||
using Lidgren.Network;
|
||||
|
||||
namespace Barotrauma.Items.Components
|
||||
{
|
||||
@@ -233,12 +232,12 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void ServerWrite(NetBuffer msg, Client c, object[] extraData = null)
|
||||
public virtual void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
|
||||
{
|
||||
msg.Write(activePicker == null ? (ushort)0 : activePicker.ID);
|
||||
}
|
||||
|
||||
public virtual void ClientRead(ServerNetObject type, NetBuffer msg, float sendingTime)
|
||||
public virtual void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
|
||||
{
|
||||
ushort pickerID = msg.ReadUInt16();
|
||||
if (pickerID == 0)
|
||||
|
||||
@@ -54,6 +54,9 @@ namespace Barotrauma.Items.Components
|
||||
[Serialize(false, false)]
|
||||
public bool RepairMultiple { get; set; }
|
||||
|
||||
[Serialize(false, false)]
|
||||
public bool RepairThroughHoles { get; set; }
|
||||
|
||||
[Serialize(0.0f, false)]
|
||||
public float FireProbability { get; set; }
|
||||
|
||||
@@ -146,10 +149,24 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
Vector2 targetPosition = item.WorldPosition;
|
||||
targetPosition += new Vector2(
|
||||
(float)Math.Cos(item.body.Rotation),
|
||||
(float)Math.Sin(item.body.Rotation)) * Range * item.body.Dir;
|
||||
Vector2 rayStart;
|
||||
Vector2 sourcePos = character?.AnimController == null ? item.SimPosition : character.AnimController.AimSourceSimPos;
|
||||
Vector2 barrelPos = item.SimPosition + ConvertUnits.ToSimUnits(TransformedBarrelPos);
|
||||
//make sure there's no obstacles between the base of the item (or the shoulder of the character) and the end of the barrel
|
||||
if (Submarine.PickBody(sourcePos, barrelPos, collisionCategory: Physics.CollisionWall | Physics.CollisionLevel | Physics.CollisionItemBlocking) == null)
|
||||
{
|
||||
//no obstacles -> we start the raycast at the end of the barrel
|
||||
rayStart = ConvertUnits.ToSimUnits(item.WorldPosition + TransformedBarrelPos);
|
||||
}
|
||||
else
|
||||
{
|
||||
rayStart = ConvertUnits.ToSimUnits(item.WorldPosition);
|
||||
}
|
||||
|
||||
Vector2 rayEnd = rayStart +
|
||||
ConvertUnits.ToSimUnits(new Vector2(
|
||||
(float)Math.Cos(item.body.Rotation),
|
||||
(float)Math.Sin(item.body.Rotation)) * Range * item.body.Dir);
|
||||
|
||||
List<Body> ignoredBodies = new List<Body>();
|
||||
foreach (Limb limb in character.AnimController.Limbs)
|
||||
@@ -161,11 +178,8 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
IsActive = true;
|
||||
activeTimer = 0.1f;
|
||||
|
||||
Vector2 rayStart = ConvertUnits.ToSimUnits(item.WorldPosition);
|
||||
Vector2 rayEnd = ConvertUnits.ToSimUnits(targetPosition);
|
||||
|
||||
debugRayStartPos = item.WorldPosition;
|
||||
|
||||
debugRayStartPos = ConvertUnits.ToDisplayUnits(rayStart);
|
||||
debugRayEndPos = ConvertUnits.ToDisplayUnits(rayEnd);
|
||||
|
||||
if (character.Submarine == null)
|
||||
@@ -203,7 +217,7 @@ namespace Barotrauma.Items.Components
|
||||
float lastPickedFraction = 0.0f;
|
||||
if (RepairMultiple)
|
||||
{
|
||||
var bodies = Submarine.PickBodies(rayStart, rayEnd, ignoredBodies, collisionCategories, ignoreSensors: false, allowInsideFixture: true);
|
||||
var bodies = Submarine.PickBodies(rayStart, rayEnd, ignoredBodies, collisionCategories, ignoreSensors: RepairThroughHoles, allowInsideFixture: true);
|
||||
lastPickedFraction = Submarine.LastPickedFraction;
|
||||
Type lastHitType = null;
|
||||
hitCharacters.Clear();
|
||||
@@ -243,7 +257,7 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
FixBody(user, deltaTime, degreeOfSuccess,
|
||||
Submarine.PickBody(rayStart, rayEnd,
|
||||
ignoredBodies, collisionCategories, ignoreSensors: false,
|
||||
ignoredBodies, collisionCategories, ignoreSensors: RepairThroughHoles,
|
||||
customPredicate: (Fixture f) => { return f?.Body?.UserData != null; },
|
||||
allowInsideFixture: true));
|
||||
lastPickedFraction = Submarine.LastPickedFraction;
|
||||
@@ -324,6 +338,7 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
else if (targetBody.UserData is Character targetCharacter)
|
||||
{
|
||||
if (targetCharacter.Removed) { return false; }
|
||||
targetCharacter.LastDamageSource = item;
|
||||
ApplyStatusEffectsOnTarget(user, deltaTime, ActionType.OnUse, new List<ISerializableEntity>() { targetCharacter });
|
||||
FixCharacterProjSpecific(user, deltaTime, targetCharacter);
|
||||
@@ -331,6 +346,7 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
else if (targetBody.UserData is Limb targetLimb)
|
||||
{
|
||||
if (targetLimb.character == null || targetLimb.character.Removed) { return false; }
|
||||
targetLimb.character.LastDamageSource = item;
|
||||
ApplyStatusEffectsOnTarget(user, deltaTime, ActionType.OnUse, new List<ISerializableEntity>() { targetLimb.character, targetLimb });
|
||||
FixCharacterProjSpecific(user, deltaTime, targetLimb.character);
|
||||
@@ -506,9 +522,9 @@ namespace Barotrauma.Items.Components
|
||||
if (propertyName != "stuck") { continue; }
|
||||
if (door.SerializableProperties == null || !door.SerializableProperties.TryGetValue(propertyName, out SerializableProperty property)) { continue; }
|
||||
object value = property.GetValue(target);
|
||||
if (value.GetType() == typeof(float))
|
||||
if (door.Stuck > 0)
|
||||
{
|
||||
var progressBar = user.UpdateHUDProgressBar(door, door.Item.WorldPosition, (float)value / 100, Color.DarkGray * 0.5f, Color.White);
|
||||
var progressBar = user.UpdateHUDProgressBar(door, door.Item.WorldPosition, door.Stuck / 100, Color.DarkGray * 0.5f, Color.White);
|
||||
if (progressBar != null) { progressBar.Size = new Vector2(60.0f, 20.0f); }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,12 +6,10 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
class Throwable : Holdable
|
||||
{
|
||||
float throwForce;
|
||||
private float throwForce, throwPos;
|
||||
private bool throwing, throwDone;
|
||||
|
||||
float throwPos;
|
||||
|
||||
bool throwing;
|
||||
bool throwDone;
|
||||
private bool midAir;
|
||||
|
||||
[Serialize(1.0f, false)]
|
||||
public float ThrowForce
|
||||
@@ -57,7 +55,17 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
public override void Update(float deltaTime, Camera cam)
|
||||
{
|
||||
if (!item.body.Enabled) return;
|
||||
if (!item.body.Enabled) { return; }
|
||||
if (midAir)
|
||||
{
|
||||
if (item.body.LinearVelocity.LengthSquared() < 0.01f)
|
||||
{
|
||||
item.body.CollidesWith = Physics.CollisionWall | Physics.CollisionLevel | Physics.CollisionPlatform;
|
||||
midAir = false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (picker == null || picker.Removed || !picker.HasSelectedItem(item))
|
||||
{
|
||||
IsActive = false;
|
||||
@@ -113,6 +121,10 @@ namespace Barotrauma.Items.Components
|
||||
item.Drop(thrower, createNetworkEvent: GameMain.NetworkMember == null || GameMain.NetworkMember.IsServer);
|
||||
item.body.ApplyLinearImpulse(throwVector * throwForce * item.body.Mass * 3.0f, maxVelocity: NetConfig.MaxPhysicsBodyVelocity);
|
||||
|
||||
//disable platform collisions until the item comes back to rest again
|
||||
item.body.CollidesWith = Physics.CollisionWall | Physics.CollisionLevel;
|
||||
midAir = true;
|
||||
|
||||
ac.GetLimb(LimbType.Head).body.ApplyLinearImpulse(throwVector * 10.0f, maxVelocity: NetConfig.MaxPhysicsBodyVelocity);
|
||||
ac.GetLimb(LimbType.Torso).body.ApplyLinearImpulse(throwVector * 10.0f, maxVelocity: NetConfig.MaxPhysicsBodyVelocity);
|
||||
|
||||
|
||||
@@ -82,13 +82,14 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (AITarget != null) AITarget.Enabled = value;
|
||||
isActive = value;
|
||||
}
|
||||
}
|
||||
|
||||
private bool drawable = true;
|
||||
|
||||
public List<PropertyConditional> IsActiveConditionals;
|
||||
|
||||
public bool Drawable
|
||||
{
|
||||
get { return drawable; }
|
||||
@@ -208,11 +209,6 @@ namespace Barotrauma.Items.Components
|
||||
set;
|
||||
}
|
||||
|
||||
public AITarget AITarget
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// How useful the item is in combat? Used by AI to decide which item it should use as a weapon. For the sake of clarity, use a value between 0 and 100 (not enforced).
|
||||
@@ -267,6 +263,15 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
switch (subElement.Name.ToString().ToLowerInvariant())
|
||||
{
|
||||
case "activeconditional":
|
||||
case "isactive":
|
||||
IsActiveConditionals = IsActiveConditionals ?? new List<PropertyConditional>();
|
||||
foreach (XAttribute attribute in subElement.Attributes())
|
||||
{
|
||||
if (attribute.Name.ToString().ToLowerInvariant() == "targetitemcomponent") { continue; }
|
||||
IsActiveConditionals.Add(new PropertyConditional(attribute));
|
||||
}
|
||||
break;
|
||||
case "requireditem":
|
||||
case "requireditems":
|
||||
RelatedItem ri = RelatedItem.Load(subElement, item.Name);
|
||||
@@ -308,12 +313,6 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
effectList.Add(statusEffect);
|
||||
|
||||
break;
|
||||
case "aitarget":
|
||||
AITarget = new AITarget(item, subElement)
|
||||
{
|
||||
Enabled = isActive
|
||||
};
|
||||
break;
|
||||
default:
|
||||
if (LoadElemProjSpecific(subElement)) break;
|
||||
@@ -474,12 +473,6 @@ namespace Barotrauma.Items.Components
|
||||
delayedCorrectionCoroutine = null;
|
||||
}
|
||||
|
||||
if (AITarget != null)
|
||||
{
|
||||
AITarget.Remove();
|
||||
AITarget = null;
|
||||
}
|
||||
|
||||
RemoveComponentSpecific();
|
||||
}
|
||||
|
||||
@@ -496,11 +489,6 @@ namespace Barotrauma.Items.Components
|
||||
loopingSoundChannel = null;
|
||||
}
|
||||
#endif
|
||||
if (AITarget != null)
|
||||
{
|
||||
AITarget.Remove();
|
||||
AITarget = null;
|
||||
}
|
||||
|
||||
ShallowRemoveComponentSpecific();
|
||||
}
|
||||
@@ -788,6 +776,7 @@ namespace Barotrauma.Items.Components
|
||||
public virtual void Reset()
|
||||
{
|
||||
SerializableProperties = SerializableProperty.DeserializeProperties(this, originalElement);
|
||||
if (this is Pickable) { canBePicked = true; }
|
||||
ParseMsg();
|
||||
OverrideRequiredItems(originalElement);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Barotrauma.Networking;
|
||||
using Lidgren.Network;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
@@ -84,6 +83,8 @@ namespace Barotrauma.Items.Components
|
||||
progressState = Math.Min(progressTimer / deconstructTime, 1.0f);
|
||||
if (progressTimer > deconstructTime)
|
||||
{
|
||||
int emptySlots = outputContainer.Inventory.Items.Where(i => i == null).Count();
|
||||
|
||||
foreach (DeconstructItem deconstructProduct in targetItem.Prefab.DeconstructItems)
|
||||
{
|
||||
float percentageHealth = targetItem.Condition / targetItem.Prefab.Health;
|
||||
@@ -100,13 +101,14 @@ namespace Barotrauma.Items.Components
|
||||
itemPrefab.Health * deconstructProduct.OutCondition;
|
||||
|
||||
//container full, drop the items outside the deconstructor
|
||||
if (outputContainer.Inventory.Items.All(i => i != null))
|
||||
if (emptySlots <= 0)
|
||||
{
|
||||
Entity.Spawner.AddToSpawnQueue(itemPrefab, item.Position, item.Submarine, condition);
|
||||
}
|
||||
else
|
||||
{
|
||||
Entity.Spawner.AddToSpawnQueue(itemPrefab, outputContainer.Inventory, condition);
|
||||
emptySlots--;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -196,6 +198,7 @@ namespace Barotrauma.Items.Components
|
||||
if (inputContainer.Inventory.Items.All(i => i == null)) { active = false; }
|
||||
|
||||
IsActive = active;
|
||||
currPowerConsumption = IsActive ? powerConsumption : 0.0f;
|
||||
|
||||
#if SERVER
|
||||
if (user != null)
|
||||
|
||||
@@ -3,7 +3,6 @@ using System;
|
||||
using System.Globalization;
|
||||
using System.Xml.Linq;
|
||||
using Barotrauma.Networking;
|
||||
using Lidgren.Network;
|
||||
|
||||
namespace Barotrauma.Items.Components
|
||||
{
|
||||
@@ -98,11 +97,17 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
UpdatePropellerDamage(deltaTime);
|
||||
|
||||
if (item.AiTarget != null)
|
||||
{
|
||||
var aiTarget = item.AiTarget;
|
||||
aiTarget.SoundRange = MathHelper.Lerp(aiTarget.MinSoundRange, aiTarget.MaxSoundRange, currForce.Length() / maxForce);
|
||||
}
|
||||
if (item.CurrentHull != null)
|
||||
{
|
||||
item.CurrentHull.AiTarget.SoundRange = Math.Max(currForce.Length(), item.CurrentHull.AiTarget.SoundRange);
|
||||
var aiTarget = item.CurrentHull.AiTarget;
|
||||
float noise = MathHelper.Lerp(aiTarget.MinSoundRange, aiTarget.MaxSoundRange, currForce.Length() / maxForce);
|
||||
aiTarget.SoundRange = Math.Max(noise, aiTarget.SoundRange);
|
||||
}
|
||||
|
||||
#if CLIENT
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Barotrauma.Networking;
|
||||
using Lidgren.Network;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
@@ -12,6 +12,8 @@ namespace Barotrauma.Items.Components
|
||||
private float maxFlow;
|
||||
|
||||
private float? targetLevel;
|
||||
|
||||
private float controlLockTimer;
|
||||
|
||||
private bool hasPower;
|
||||
|
||||
@@ -57,18 +59,24 @@ namespace Barotrauma.Items.Components
|
||||
currFlow = 0.0f;
|
||||
hasPower = false;
|
||||
|
||||
controlLockTimer -= deltaTime;
|
||||
if (targetLevel != null)
|
||||
{
|
||||
float hullPercentage = 0.0f;
|
||||
if (item.CurrentHull != null) hullPercentage = (item.CurrentHull.WaterVolume / item.CurrentHull.Volume) * 100.0f;
|
||||
if (item.CurrentHull != null) { hullPercentage = (item.CurrentHull.WaterVolume / item.CurrentHull.Volume) * 100.0f; }
|
||||
FlowPercentage = ((float)targetLevel - hullPercentage) * 10.0f;
|
||||
|
||||
if (controlLockTimer <= 0.0f)
|
||||
{
|
||||
targetLevel = null;
|
||||
}
|
||||
}
|
||||
|
||||
currPowerConsumption = powerConsumption * Math.Abs(flowPercentage / 100.0f);
|
||||
//pumps consume more power when in a bad condition
|
||||
currPowerConsumption *= MathHelper.Lerp(2.0f, 1.0f, item.Condition / item.MaxCondition);
|
||||
|
||||
if (voltage < minVoltage) return;
|
||||
if (voltage < minVoltage) { return; }
|
||||
|
||||
UpdateProjSpecific(deltaTime);
|
||||
|
||||
@@ -109,6 +117,7 @@ namespace Barotrauma.Items.Components
|
||||
if (float.TryParse(signal, NumberStyles.Any, CultureInfo.InvariantCulture, out float tempSpeed))
|
||||
{
|
||||
flowPercentage = MathHelper.Clamp(tempSpeed, -100.0f, 100.0f);
|
||||
controlLockTimer = 0.1f;
|
||||
}
|
||||
}
|
||||
else if (connection.Name == "set_targetlevel")
|
||||
@@ -116,6 +125,7 @@ namespace Barotrauma.Items.Components
|
||||
if (float.TryParse(signal, NumberStyles.Any, CultureInfo.InvariantCulture, out float tempTarget))
|
||||
{
|
||||
targetLevel = MathHelper.Clamp((tempTarget + 100.0f) / 2.0f, 0.0f, 100.0f);
|
||||
controlLockTimer = 0.1f;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Barotrauma.Networking;
|
||||
using Lidgren.Network;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -271,7 +270,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
//calculate how much external power there is in the grid
|
||||
//(power coming from somewhere else than this reactor, e.g. batteries)
|
||||
float externalPower = CurrPowerConsumption - pt.CurrPowerConsumption;
|
||||
float externalPower = Math.Max(CurrPowerConsumption - pt.CurrPowerConsumption, 0);
|
||||
//reduce the external power from the load to prevent overloading the grid
|
||||
load = Math.Max(load, pt.PowerLoad - externalPower);
|
||||
}
|
||||
@@ -288,10 +287,17 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
if (item.CurrentHull != null)
|
||||
{
|
||||
//the sound can be heard from 20 000 display units away when running at full power
|
||||
item.CurrentHull.SoundRange = Math.Max(
|
||||
(-currPowerConsumption / MaxPowerOutput) * 20000.0f,
|
||||
item.CurrentHull.AiTarget.SoundRange);
|
||||
var aiTarget = item.CurrentHull.AiTarget;
|
||||
float range = Math.Abs(currPowerConsumption) / MaxPowerOutput;
|
||||
float noise = MathHelper.Lerp(aiTarget.MinSoundRange, aiTarget.MaxSoundRange, range);
|
||||
aiTarget.SoundRange = Math.Max(aiTarget.SoundRange, noise);
|
||||
}
|
||||
|
||||
if (item.AiTarget != null)
|
||||
{
|
||||
var aiTarget = item.AiTarget;
|
||||
float range = Math.Abs(currPowerConsumption) / MaxPowerOutput;
|
||||
aiTarget.SoundRange = MathHelper.Lerp(aiTarget.MinSoundRange, aiTarget.MaxSoundRange, range);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -439,6 +445,8 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
base.UpdateBroken(deltaTime, cam);
|
||||
|
||||
item.SendSignal(0, ((int)(temperature * 100.0f)).ToString(), "temperature_out", null);
|
||||
|
||||
currPowerConsumption = 0.0f;
|
||||
Temperature -= deltaTime * 1000.0f;
|
||||
targetFissionRate = Math.Max(targetFissionRate - deltaTime * 10.0f, 0.0f);
|
||||
|
||||
@@ -114,9 +114,9 @@ namespace Barotrauma.Items.Components
|
||||
if (value == Mode.Passive)
|
||||
{
|
||||
currentPingIndex = -1;
|
||||
if (item.CurrentHull != null)
|
||||
if (item.AiTarget != null)
|
||||
{
|
||||
item.CurrentHull.AiTarget.SectorDegrees = 360.0f;
|
||||
item.AiTarget.SectorDegrees = 360.0f;
|
||||
}
|
||||
}
|
||||
#if CLIENT
|
||||
@@ -168,15 +168,10 @@ namespace Barotrauma.Items.Components
|
||||
var activePing = activePings[currentPingIndex];
|
||||
if (activePing.State > 1.0f)
|
||||
{
|
||||
if (item.CurrentHull != null)
|
||||
{
|
||||
item.CurrentHull.AiTarget.SoundRange = Math.Max(Range * activePing.State / zoom, item.CurrentHull.AiTarget.SoundRange);
|
||||
item.CurrentHull.AiTarget.SectorDegrees = activePing.IsDirectional ? DirectionalPingSector : 360.0f;
|
||||
item.CurrentHull.AiTarget.SectorDir = new Vector2(pingDirection.X, -pingDirection.Y);
|
||||
}
|
||||
if (item.AiTarget != null)
|
||||
{
|
||||
item.AiTarget.SoundRange = Math.Max(Range * activePing.State / zoom, item.AiTarget.SoundRange);
|
||||
float range = MathUtils.InverseLerp(item.AiTarget.MinSoundRange, item.AiTarget.MaxSoundRange, Range * activePing.State / zoom);
|
||||
item.AiTarget.SoundRange = MathHelper.Lerp(item.AiTarget.MinSoundRange, item.AiTarget.MaxSoundRange, range);
|
||||
item.AiTarget.SectorDegrees = activePing.IsDirectional ? DirectionalPingSector : 360.0f;
|
||||
item.AiTarget.SectorDir = new Vector2(pingDirection.X, -pingDirection.Y);
|
||||
}
|
||||
@@ -200,9 +195,9 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
else
|
||||
{
|
||||
if (item.CurrentHull != null)
|
||||
if (item.AiTarget != null)
|
||||
{
|
||||
item.CurrentHull.AiTarget.SectorDegrees = 360.0f;
|
||||
item.AiTarget.SectorDegrees = 360.0f;
|
||||
}
|
||||
currentPingIndex = -1;
|
||||
aiPingCheckPending = false;
|
||||
@@ -345,7 +340,7 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
public void ServerRead(ClientNetObject type, Lidgren.Network.NetBuffer msg, Client c)
|
||||
public void ServerRead(ClientNetObject type, IReadMessage msg, Client c)
|
||||
{
|
||||
bool isActive = msg.ReadBoolean();
|
||||
bool directionalPing = useDirectionalPing;
|
||||
@@ -388,7 +383,7 @@ namespace Barotrauma.Items.Components
|
||||
#endif
|
||||
}
|
||||
|
||||
public void ServerWrite(Lidgren.Network.NetBuffer msg, Client c, object[] extraData = null)
|
||||
public void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
|
||||
{
|
||||
msg.Write(currentMode == Mode.Active);
|
||||
if (currentMode == Mode.Active)
|
||||
|
||||
@@ -522,7 +522,7 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
public void ServerRead(ClientNetObject type, Lidgren.Network.NetBuffer msg, Barotrauma.Networking.Client c)
|
||||
public void ServerRead(ClientNetObject type, IReadMessage msg, Barotrauma.Networking.Client c)
|
||||
{
|
||||
bool autoPilot = msg.ReadBoolean();
|
||||
bool dockingButtonClicked = msg.ReadBoolean();
|
||||
@@ -537,8 +537,8 @@ namespace Barotrauma.Items.Components
|
||||
if (maintainPos)
|
||||
{
|
||||
newPosToMaintain = new Vector2(
|
||||
msg.ReadFloat(),
|
||||
msg.ReadFloat());
|
||||
msg.ReadSingle(),
|
||||
msg.ReadSingle());
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -547,7 +547,7 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
else
|
||||
{
|
||||
newSteeringInput = new Vector2(msg.ReadFloat(), msg.ReadFloat());
|
||||
newSteeringInput = new Vector2(msg.ReadSingle(), msg.ReadSingle());
|
||||
}
|
||||
|
||||
if (!item.CanClientAccess(c)) return;
|
||||
@@ -587,7 +587,7 @@ namespace Barotrauma.Items.Components
|
||||
unsentChanges = true;
|
||||
}
|
||||
|
||||
public void ServerWrite(Lidgren.Network.NetBuffer msg, Barotrauma.Networking.Client c, object[] extraData = null)
|
||||
public void ServerWrite(IWriteMessage msg, Barotrauma.Networking.Client c, object[] extraData = null)
|
||||
{
|
||||
msg.Write(autoPilot);
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Barotrauma.Networking;
|
||||
using Lidgren.Network;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
@@ -64,6 +64,13 @@ namespace Barotrauma.Items.Components
|
||||
set;
|
||||
}
|
||||
|
||||
[Serialize(false, false)]
|
||||
public bool Overload
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
//can the component transfer power
|
||||
private bool canTransfer;
|
||||
public bool CanTransfer
|
||||
@@ -115,6 +122,8 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
base.UpdateBroken(deltaTime, cam);
|
||||
|
||||
Overload = false;
|
||||
|
||||
if (!isBroken)
|
||||
{
|
||||
powerLoad = 0.0f;
|
||||
@@ -128,7 +137,8 @@ namespace Barotrauma.Items.Components
|
||||
public override void Update(float deltaTime, Camera cam)
|
||||
{
|
||||
RefreshConnections();
|
||||
if (!CanTransfer) return;
|
||||
|
||||
if (!CanTransfer) { return; }
|
||||
|
||||
if (isBroken)
|
||||
{
|
||||
@@ -143,6 +153,8 @@ namespace Barotrauma.Items.Components
|
||||
return;
|
||||
}
|
||||
|
||||
Overload = false;
|
||||
|
||||
//reset and recalculate the power generated/consumed
|
||||
//by the constructions connected to the grid
|
||||
fullPower = 0.0f;
|
||||
@@ -156,10 +168,11 @@ namespace Barotrauma.Items.Components
|
||||
foreach (Powered p in connectedList)
|
||||
{
|
||||
PowerTransfer pt = p as PowerTransfer;
|
||||
if (pt == null || pt.updateCount == 0) continue;
|
||||
if (pt == null || pt.updateCount == 0) { continue; }
|
||||
|
||||
if (pt is RelayComponent != this is RelayComponent) continue;
|
||||
if (pt is RelayComponent != this is RelayComponent) { continue; }
|
||||
|
||||
pt.Overload = false;
|
||||
pt.powerLoad += (fullLoad - pt.powerLoad) / inertia;
|
||||
pt.currPowerConsumption += (-fullPower - pt.currPowerConsumption) / inertia;
|
||||
|
||||
@@ -173,38 +186,38 @@ namespace Barotrauma.Items.Components
|
||||
pt.Item.SendSignal(0, "", "power", null, voltage);
|
||||
pt.Item.SendSignal(0, "", "power_out", null, voltage);
|
||||
|
||||
#if CLIENT
|
||||
//damage the item if voltage is too high
|
||||
//(except if running as a client)
|
||||
if (GameMain.Client != null) continue;
|
||||
#endif
|
||||
|
||||
//items in a bad condition are more sensitive to overvoltage
|
||||
float maxOverVoltage = MathHelper.Lerp(OverloadVoltage * 0.75f, OverloadVoltage, item.Condition / item.MaxCondition);
|
||||
float maxOverVoltage = MathHelper.Lerp(OverloadVoltage * 0.75f, OverloadVoltage, pt.item.Condition / pt.item.MaxCondition);
|
||||
maxOverVoltage = Math.Max(OverloadVoltage, 1.0f);
|
||||
|
||||
//if the item can't be fixed, don't allow it to break
|
||||
if (!item.Repairables.Any() || !CanBeOverloaded) continue;
|
||||
if (!pt.item.Repairables.Any() || !pt.CanBeOverloaded) { continue; }
|
||||
|
||||
//relays don't blow up if the power is higher than load, only if the output is high enough
|
||||
//(i.e. enough power passing through the relay)
|
||||
if (this is RelayComponent) continue;
|
||||
if (pt is RelayComponent) { continue; }
|
||||
|
||||
if (-pt.currPowerConsumption < Math.Max(pt.powerLoad, 200.0f) * maxOverVoltage) continue;
|
||||
if (-pt.currPowerConsumption < Math.Max(pt.powerLoad, 200.0f) * maxOverVoltage) { continue; }
|
||||
|
||||
pt.Overload = true;
|
||||
#if CLIENT
|
||||
//damage the item if voltage is too high
|
||||
//(except if running as a client)
|
||||
if (GameMain.Client != null) { continue; }
|
||||
#endif
|
||||
float prevCondition = pt.item.Condition;
|
||||
pt.item.Condition -= deltaTime * 10.0f;
|
||||
|
||||
if (pt.item.Condition <= 0.0f && prevCondition > 0.0f)
|
||||
{
|
||||
#if CLIENT
|
||||
SoundPlayer.PlaySound("zap", item.WorldPosition, hullGuess: item.CurrentHull);
|
||||
SoundPlayer.PlaySound("zap", item.WorldPosition, hullGuess: pt.item.CurrentHull);
|
||||
|
||||
Vector2 baseVel = Rand.Vector(300.0f);
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
var particle = GameMain.ParticleManager.CreateParticle("spark", pt.item.WorldPosition,
|
||||
baseVel + Rand.Vector(100.0f), 0.0f, item.CurrentHull);
|
||||
baseVel + Rand.Vector(100.0f), 0.0f, pt.item.CurrentHull);
|
||||
|
||||
if (particle != null) particle.Size *= Rand.Range(0.5f, 1.0f);
|
||||
}
|
||||
@@ -214,8 +227,8 @@ namespace Barotrauma.Items.Components
|
||||
GameMain.GameSession.EventManager.CurrentIntensity : 0.5f;
|
||||
|
||||
//higher probability for fires if the current intensity is low
|
||||
if (FireProbability > 0.0f &&
|
||||
Rand.Range(0.0f, 1.0f) < MathHelper.Lerp(FireProbability, FireProbability * 0.1f, currentIntensity))
|
||||
if (pt.FireProbability > 0.0f &&
|
||||
Rand.Range(0.0f, 1.0f) < MathHelper.Lerp(pt.FireProbability, pt.FireProbability * 0.1f, currentIntensity))
|
||||
{
|
||||
new FireSource(pt.item.WorldPosition);
|
||||
}
|
||||
|
||||
@@ -409,11 +409,11 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
private bool OnProjectileCollision(Fixture target, Vector2 collisionNormal)
|
||||
{
|
||||
if (User != null && User.Removed) User = null;
|
||||
if (User != null && User.Removed) { User = null; }
|
||||
|
||||
if (IgnoredBodies.Contains(target.Body)) return false;
|
||||
if (IgnoredBodies.Contains(target.Body)) { return false; }
|
||||
|
||||
if (target.UserData is Item) return false;
|
||||
if (target.UserData is Item) { return false; }
|
||||
|
||||
if (target.CollisionCategories == Physics.CollisionCharacter && !(target.Body.UserData is Limb))
|
||||
{
|
||||
@@ -447,10 +447,21 @@ namespace Barotrauma.Items.Components
|
||||
if (attack != null) { attackResult = attack.DoDamage(User, structure, item.WorldPosition, 1.0f); }
|
||||
}
|
||||
|
||||
if (character != null) character.LastDamageSource = item;
|
||||
ApplyStatusEffects(ActionType.OnUse, 1.0f, character, target.Body.UserData as Limb, user: user);
|
||||
ApplyStatusEffects(ActionType.OnImpact, 1.0f, character, target.Body.UserData as Limb, user: user);
|
||||
|
||||
if (character != null) { character.LastDamageSource = item; }
|
||||
|
||||
if (GameMain.NetworkMember == null || GameMain.NetworkMember.IsServer)
|
||||
{
|
||||
ApplyStatusEffects(ActionType.OnUse, 1.0f, character, target.Body.UserData as Limb, user: user);
|
||||
ApplyStatusEffects(ActionType.OnImpact, 1.0f, character, target.Body.UserData as Limb, user: user);
|
||||
#if SERVER
|
||||
if (GameMain.NetworkMember.IsServer)
|
||||
{
|
||||
GameMain.Server?.CreateEntityEvent(item, new object[] { NetEntityEvent.Type.ApplyStatusEffect, ActionType.OnUse });
|
||||
GameMain.Server?.CreateEntityEvent(item, new object[] { NetEntityEvent.Type.ApplyStatusEffect, ActionType.OnImpact });
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
item.body.FarseerBody.OnCollision -= OnProjectileCollision;
|
||||
|
||||
item.body.CollisionCategories = Physics.CollisionItem;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Barotrauma.Networking;
|
||||
using Lidgren.Network;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Linq;
|
||||
@@ -10,12 +9,15 @@ namespace Barotrauma.Items.Components
|
||||
partial class Repairable : ItemComponent, IServerSerializable, IClientSerializable
|
||||
{
|
||||
public static float SkillIncreasePerRepair = 5.0f;
|
||||
public static float SkillIncreasePerSabotage = 3.0f;
|
||||
|
||||
private string header;
|
||||
|
||||
private float deteriorationTimer;
|
||||
private float deteriorateAlwaysResetTimer;
|
||||
|
||||
bool wasBroken;
|
||||
bool wasGoodCondition;
|
||||
|
||||
public float LastActiveTime;
|
||||
|
||||
@@ -40,14 +42,21 @@ namespace Barotrauma.Items.Components
|
||||
set;
|
||||
}
|
||||
|
||||
[Serialize(50.0f, true), Editable(MinValueFloat = 0.0f, MaxValueFloat = 100.0f, ToolTip = "The item won't deteriorate spontaneously if the condition is below this value. For example, if set to 10, the condition will spontaneously drop to 10 and then stop dropping (unless the item is damaged further by external factors).")]
|
||||
[Serialize(50.0f, true), Editable(MinValueFloat = 0.0f, MaxValueFloat = 100.0f, ToolTip = "The item won't deteriorate spontaneously if the condition is below this value. For example, if set to 10, the condition will spontaneously drop to 10 and then stop dropping (unless the item is damaged further by external factors). Percentages of max condition.")]
|
||||
public float MinDeteriorationCondition
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[Serialize(80.0f, true), Editable(MinValueFloat = 0.0f, MaxValueFloat = 100.0f, ToolTip = "The condition of the item has to be below this before the repair UI becomes usable.")]
|
||||
[Serialize(0f, true)]
|
||||
public float MinSabotageCondition
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
[Serialize(80.0f, true), Editable(MinValueFloat = 0.0f, MaxValueFloat = 100.0f, ToolTip = "The condition of the item has to be below this before the repair UI becomes usable. Percentages of max condition.")]
|
||||
public float ShowRepairUIThreshold
|
||||
{
|
||||
get;
|
||||
@@ -76,16 +85,20 @@ namespace Barotrauma.Items.Components
|
||||
set;
|
||||
}
|
||||
|
||||
private Character currentFixer;
|
||||
public Character CurrentFixer
|
||||
public Character CurrentFixer { get; private set; }
|
||||
|
||||
public enum FixActions : int
|
||||
{
|
||||
get { return currentFixer; }
|
||||
set
|
||||
{
|
||||
if (currentFixer == value || item.IsFullCondition) return;
|
||||
if (currentFixer != null) currentFixer.AnimController.Anim = AnimController.Animation.None;
|
||||
currentFixer = value;
|
||||
}
|
||||
None = 0,
|
||||
Repair = 1,
|
||||
Sabotage = 2
|
||||
}
|
||||
|
||||
private FixActions currentFixerAction = FixActions.None;
|
||||
public FixActions CurrentFixerAction
|
||||
{
|
||||
get => currentFixerAction;
|
||||
private set { currentFixerAction = value; }
|
||||
}
|
||||
|
||||
public Repairable(Item item, XElement element)
|
||||
@@ -105,18 +118,41 @@ namespace Barotrauma.Items.Components
|
||||
public override void OnItemLoaded()
|
||||
{
|
||||
deteriorationTimer = Rand.Range(MinDeteriorationDelay, MaxDeteriorationDelay);
|
||||
|
||||
#if SERVER
|
||||
//let the clients know the initial deterioration delay
|
||||
item.CreateServerEvent(this);
|
||||
#endif
|
||||
}
|
||||
|
||||
partial void InitProjSpecific(XElement element);
|
||||
|
||||
public void StartRepairing(Character character)
|
||||
public bool StartRepairing(Character character, FixActions action)
|
||||
{
|
||||
CurrentFixer = character;
|
||||
if (character == null || character.IsDead || action == FixActions.None)
|
||||
{
|
||||
DebugConsole.ThrowError("Invalid repair command!");
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
CurrentFixer = character;
|
||||
CurrentFixerAction = action;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public bool StopRepairing(Character character)
|
||||
{
|
||||
if (CurrentFixer == character)
|
||||
{
|
||||
CurrentFixer.AnimController.Anim = AnimController.Animation.None;
|
||||
CurrentFixer = null;
|
||||
currentFixerAction = FixActions.None;
|
||||
#if SERVER
|
||||
item.CreateServerEvent(this);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public override void UpdateBroken(float deltaTime, Camera cam)
|
||||
@@ -129,7 +165,7 @@ namespace Barotrauma.Items.Components
|
||||
deteriorationTimer = Rand.Range(MinDeteriorationDelay, MaxDeteriorationDelay);
|
||||
item.Condition = item.Prefab.Health;
|
||||
#if SERVER
|
||||
//let the clients know the initial deterioration delay
|
||||
//let the clients know the deterioration delay
|
||||
item.CreateServerEvent(this);
|
||||
#endif
|
||||
}
|
||||
@@ -140,6 +176,18 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
if (CurrentFixer == null)
|
||||
{
|
||||
if (deteriorateAlwaysResetTimer > 0.0f)
|
||||
{
|
||||
deteriorateAlwaysResetTimer -= deltaTime;
|
||||
if (deteriorateAlwaysResetTimer <= 0.0f)
|
||||
{
|
||||
DeteriorateAlways = false;
|
||||
#if SERVER
|
||||
//let the clients know the deterioration delay
|
||||
item.CreateServerEvent(this);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
if (!ShouldDeteriorate()) { return; }
|
||||
if (item.Condition > 0.0f)
|
||||
{
|
||||
@@ -155,7 +203,7 @@ namespace Barotrauma.Items.Components
|
||||
return;
|
||||
}
|
||||
|
||||
if (item.Condition > MinDeteriorationCondition)
|
||||
if (item.ConditionPercentage > MinDeteriorationCondition)
|
||||
{
|
||||
item.Condition -= DeteriorationSpeed * deltaTime;
|
||||
}
|
||||
@@ -163,10 +211,9 @@ namespace Barotrauma.Items.Components
|
||||
return;
|
||||
}
|
||||
|
||||
if (Item.IsFullCondition || CurrentFixer.SelectedConstruction != item || !currentFixer.CanInteractWith(item))
|
||||
if (CurrentFixer != null && (CurrentFixer.SelectedConstruction != item || !CurrentFixer.CanInteractWith(item) || CurrentFixer.IsDead))
|
||||
{
|
||||
currentFixer.AnimController.Anim = AnimController.Animation.None;
|
||||
currentFixer = null;
|
||||
StopRepairing(CurrentFixer);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -177,44 +224,89 @@ namespace Barotrauma.Items.Components
|
||||
float successFactor = requiredSkills.Count == 0 ? 1.0f : 0.0f;
|
||||
|
||||
//item must have been below the repair threshold for the player to get an achievement or XP for repairing it
|
||||
if (item.Condition < ShowRepairUIThreshold)
|
||||
if (item.ConditionPercentage < ShowRepairUIThreshold)
|
||||
{
|
||||
wasBroken = true;
|
||||
}
|
||||
if (item.ConditionPercentage > MinSabotageCondition)
|
||||
{
|
||||
wasGoodCondition = true;
|
||||
}
|
||||
|
||||
float fixDuration = MathHelper.Lerp(FixDurationLowSkill, FixDurationHighSkill, successFactor);
|
||||
if (fixDuration <= 0.0f)
|
||||
if (currentFixerAction == FixActions.Repair)
|
||||
{
|
||||
item.Condition = item.MaxCondition;
|
||||
if (fixDuration <= 0.0f)
|
||||
{
|
||||
item.Condition = item.MaxCondition;
|
||||
}
|
||||
else
|
||||
{
|
||||
float conditionIncrease = deltaTime / (fixDuration / item.MaxCondition);
|
||||
item.Condition += conditionIncrease;
|
||||
#if SERVER
|
||||
GameMain.Server.KarmaManager.OnItemRepaired(CurrentFixer, this, conditionIncrease);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (item.IsFullCondition)
|
||||
{
|
||||
if (wasBroken)
|
||||
{
|
||||
foreach (Skill skill in requiredSkills)
|
||||
{
|
||||
float characterSkillLevel = CurrentFixer.GetSkillLevel(skill.Identifier);
|
||||
CurrentFixer.Info.IncreaseSkillLevel(skill.Identifier,
|
||||
SkillIncreasePerRepair / Math.Max(characterSkillLevel, 1.0f),
|
||||
CurrentFixer.WorldPosition + Vector2.UnitY * 100.0f);
|
||||
}
|
||||
|
||||
SteamAchievementManager.OnItemRepaired(item, CurrentFixer);
|
||||
deteriorationTimer = Rand.Range(MinDeteriorationDelay, MaxDeteriorationDelay);
|
||||
wasBroken = false;
|
||||
}
|
||||
StopRepairing(CurrentFixer);
|
||||
}
|
||||
}
|
||||
else if (currentFixerAction == FixActions.Sabotage)
|
||||
{
|
||||
if (fixDuration <= 0.0f)
|
||||
{
|
||||
item.Condition = item.MaxCondition * (MinSabotageCondition / 100);
|
||||
}
|
||||
else
|
||||
{
|
||||
float conditionDecrease = deltaTime / (fixDuration / item.MaxCondition);
|
||||
item.Condition -= conditionDecrease;
|
||||
}
|
||||
|
||||
if (item.ConditionPercentage <= MinSabotageCondition)
|
||||
{
|
||||
if (wasGoodCondition)
|
||||
{
|
||||
foreach (Skill skill in requiredSkills)
|
||||
{
|
||||
float characterSkillLevel = CurrentFixer.GetSkillLevel(skill.Identifier);
|
||||
CurrentFixer.Info.IncreaseSkillLevel(skill.Identifier,
|
||||
SkillIncreasePerSabotage / Math.Max(characterSkillLevel, 1.0f),
|
||||
CurrentFixer.WorldPosition + Vector2.UnitY * 100.0f);
|
||||
}
|
||||
|
||||
deteriorationTimer = 0.0f;
|
||||
deteriorateAlwaysResetTimer = item.Condition / DeteriorationSpeed;
|
||||
DeteriorateAlways = true;
|
||||
item.Condition = item.MaxCondition * (MinSabotageCondition / 100);
|
||||
wasGoodCondition = false;
|
||||
}
|
||||
StopRepairing(CurrentFixer);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
float conditionIncrease = deltaTime / (fixDuration / item.MaxCondition);
|
||||
item.Condition += conditionIncrease;
|
||||
#if SERVER
|
||||
GameMain.Server.KarmaManager.OnItemRepaired(CurrentFixer, this, conditionIncrease);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (wasBroken && item.IsFullCondition)
|
||||
{
|
||||
foreach (Skill skill in requiredSkills)
|
||||
{
|
||||
float characterSkillLevel = CurrentFixer.GetSkillLevel(skill.Identifier);
|
||||
CurrentFixer.Info.IncreaseSkillLevel(skill.Identifier,
|
||||
SkillIncreasePerRepair / Math.Max(characterSkillLevel, 1.0f),
|
||||
CurrentFixer.WorldPosition + Vector2.UnitY * 100.0f);
|
||||
}
|
||||
SteamAchievementManager.OnItemRepaired(item, currentFixer);
|
||||
deteriorationTimer = Rand.Range(MinDeteriorationDelay, MaxDeteriorationDelay);
|
||||
wasBroken = false;
|
||||
#if SERVER
|
||||
item.CreateServerEvent(this);
|
||||
#endif
|
||||
throw new NotImplementedException(currentFixerAction.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
partial void UpdateProjSpecific(float deltaTime);
|
||||
|
||||
private bool ShouldDeteriorate()
|
||||
|
||||
@@ -218,6 +218,16 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
public void SetWire(int index, Wire wire)
|
||||
{
|
||||
Wire previousWire = wires[index];
|
||||
if (wire != previousWire && previousWire != null)
|
||||
{
|
||||
var otherConnection = previousWire.OtherConnection(this);
|
||||
if (otherConnection != null)
|
||||
{
|
||||
otherConnection.recipientsDirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
wires[index] = wire;
|
||||
recipientsDirty = true;
|
||||
if (wire != null)
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using Barotrauma.Networking;
|
||||
using FarseerPhysics;
|
||||
using Lidgren.Network;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -19,7 +18,9 @@ namespace Barotrauma.Items.Components
|
||||
/// Wires that have been disconnected from the panel, but not removed completely (visible at the bottom of the connection panel).
|
||||
/// </summary>
|
||||
public readonly HashSet<Wire> DisconnectedWires = new HashSet<Wire>();
|
||||
|
||||
|
||||
private List<ushort> disconnectedWireIds;
|
||||
|
||||
[Serialize(false, true), Editable(ToolTip = "Locked connection panels cannot be rewired in-game.")]
|
||||
public bool Locked
|
||||
{
|
||||
@@ -64,6 +65,19 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
c.ConnectLinked();
|
||||
}
|
||||
|
||||
if (disconnectedWireIds != null)
|
||||
{
|
||||
foreach (ushort disconnectedWireId in disconnectedWireIds)
|
||||
{
|
||||
if (!(Entity.FindEntityByID(disconnectedWireId) is Item wireItem)) { continue; }
|
||||
Wire wire = wireItem.GetComponent<Wire>();
|
||||
if (wire != null)
|
||||
{
|
||||
DisconnectedWires.Add(wire);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnItemLoaded()
|
||||
@@ -193,6 +207,8 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
loadedConnections[i].wireId.CopyTo(Connections[i].wireId, 0);
|
||||
}
|
||||
|
||||
disconnectedWireIds = element.GetAttributeUshortArray("disconnectedwires", new ushort[0]).ToList();
|
||||
}
|
||||
|
||||
public override XElement Save(XElement parentElement)
|
||||
@@ -204,6 +220,11 @@ namespace Barotrauma.Items.Components
|
||||
c.Save(componentElement);
|
||||
}
|
||||
|
||||
if (DisconnectedWires.Count > 0)
|
||||
{
|
||||
componentElement.Add(new XAttribute("disconnectedwires", string.Join(",", DisconnectedWires.Select(w => w.Item.ID))));
|
||||
}
|
||||
|
||||
return componentElement;
|
||||
}
|
||||
|
||||
@@ -214,6 +235,14 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
protected override void RemoveComponentSpecific()
|
||||
{
|
||||
foreach (Wire wire in DisconnectedWires.ToList())
|
||||
{
|
||||
if (wire.OtherConnection(null) == null) //wire not connected to anything else
|
||||
{
|
||||
wire.Item.Drop(null);
|
||||
}
|
||||
}
|
||||
|
||||
DisconnectedWires.Clear();
|
||||
foreach (Connection c in Connections)
|
||||
{
|
||||
@@ -233,7 +262,7 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
public void ClientWrite(NetBuffer msg, object[] extraData = null)
|
||||
public void ClientWrite(IWriteMessage msg, object[] extraData = null)
|
||||
{
|
||||
foreach (Connection connection in Connections)
|
||||
{
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Barotrauma.Networking;
|
||||
using Lidgren.Network;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
using System;
|
||||
using System.Xml.Linq;
|
||||
using Barotrauma.Networking;
|
||||
using Lidgren.Network;
|
||||
#if CLIENT
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using Barotrauma.Lights;
|
||||
@@ -251,10 +250,6 @@ namespace Barotrauma.Items.Components
|
||||
light.Range = range;
|
||||
#endif
|
||||
}
|
||||
if (AITarget != null)
|
||||
{
|
||||
UpdateAITarget(AITarget);
|
||||
}
|
||||
if (item.AiTarget != null)
|
||||
{
|
||||
UpdateAITarget(item.AiTarget);
|
||||
@@ -267,6 +262,7 @@ namespace Barotrauma.Items.Components
|
||||
public override void UpdateBroken(float deltaTime, Camera cam)
|
||||
{
|
||||
light.Color = Color.Transparent;
|
||||
lightBrightness = 0.0f;
|
||||
}
|
||||
|
||||
protected override void RemoveComponentSpecific()
|
||||
@@ -298,7 +294,7 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
public void ServerWrite(NetBuffer msg, Client c, object[] extraData = null)
|
||||
public void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
|
||||
{
|
||||
msg.Write(IsOn);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Barotrauma.Networking;
|
||||
using Lidgren.Network;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Xml.Linq;
|
||||
@@ -104,12 +103,12 @@ namespace Barotrauma.Items.Components
|
||||
IsOn = on;
|
||||
}
|
||||
|
||||
public void ServerWrite(NetBuffer msg, Client c, object[] extraData = null)
|
||||
public void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
|
||||
{
|
||||
msg.Write(isOn);
|
||||
}
|
||||
|
||||
public void ClientRead(ServerNetObject type, NetBuffer msg, float sendingTime)
|
||||
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
|
||||
{
|
||||
SetState(msg.ReadBoolean(), true);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Barotrauma.Networking;
|
||||
using Lidgren.Network;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -282,7 +281,7 @@ namespace Barotrauma.Items.Components
|
||||
Structure attachTarget = Structure.GetAttachTarget(item.WorldPosition);
|
||||
canPlaceNode = attachTarget != null;
|
||||
|
||||
sub = attachTarget?.Submarine;
|
||||
sub = sub ?? attachTarget?.Submarine;
|
||||
newNodePos = sub == null ?
|
||||
item.WorldPosition :
|
||||
item.WorldPosition - sub.Position - sub.HiddenSubPosition;
|
||||
@@ -333,7 +332,8 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
else
|
||||
{
|
||||
newNodePos = RoundNode(item.Position, item.CurrentHull) - sub.HiddenSubPosition;
|
||||
newNodePos = RoundNode(item.Position, item.CurrentHull);
|
||||
if (sub != null) { newNodePos -= sub.HiddenSubPosition; }
|
||||
canPlaceNode = true;
|
||||
}
|
||||
|
||||
@@ -724,7 +724,7 @@ namespace Barotrauma.Items.Components
|
||||
base.RemoveComponentSpecific();
|
||||
}
|
||||
|
||||
public void ClientRead(ServerNetObject type, NetBuffer msg, float sendingTime)
|
||||
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
|
||||
{
|
||||
int eventIndex = msg.ReadRangedInteger(0, (int)Math.Ceiling(MaxNodeCount / (float)MaxNodesPerNetworkEvent));
|
||||
int nodeCount = msg.ReadRangedInteger(0, MaxNodesPerNetworkEvent);
|
||||
@@ -738,7 +738,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
for (int i = 0; i < nodeCount; i++)
|
||||
{
|
||||
nodePositions[nodeStartIndex + i] = new Vector2(msg.ReadFloat(), msg.ReadFloat());
|
||||
nodePositions[nodeStartIndex + i] = new Vector2(msg.ReadSingle(), msg.ReadSingle());
|
||||
}
|
||||
|
||||
if (nodePositions.Any(n => !MathUtils.IsValid(n)))
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using Barotrauma.Networking;
|
||||
using FarseerPhysics;
|
||||
using Lidgren.Network;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -674,7 +673,7 @@ namespace Barotrauma.Items.Components
|
||||
}
|
||||
}
|
||||
|
||||
public void ServerWrite(NetBuffer msg, Client c, object[] extraData = null)
|
||||
public void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
|
||||
{
|
||||
Item item = (Item)extraData[2];
|
||||
msg.Write(item.Removed ? (ushort)0 : item.ID);
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using Barotrauma.Items.Components;
|
||||
using Barotrauma.Networking;
|
||||
using Lidgren.Network;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -375,7 +374,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public void SharedWrite(NetBuffer msg, object[] extraData = null)
|
||||
public void SharedWrite(IWriteMessage msg, object[] extraData = null)
|
||||
{
|
||||
for (int i = 0; i < capacity; i++)
|
||||
{
|
||||
|
||||
@@ -3,7 +3,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;
|
||||
@@ -127,6 +126,24 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public delegate bool InventoryFilter(Inventory inventory);
|
||||
public Inventory FindParentInventory(InventoryFilter filter)
|
||||
{
|
||||
if (parentInventory != null)
|
||||
{
|
||||
if (filter(parentInventory))
|
||||
{
|
||||
return parentInventory;
|
||||
}
|
||||
var owner = parentInventory.Owner as Item;
|
||||
if (owner != null)
|
||||
{
|
||||
return owner.FindParentInventory(filter);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private Item container;
|
||||
public Item Container
|
||||
{
|
||||
@@ -597,12 +614,15 @@ namespace Barotrauma
|
||||
case "fabricate":
|
||||
case "fabricable":
|
||||
case "fabricableitem":
|
||||
case "upgrade":
|
||||
break;
|
||||
case "staticbody":
|
||||
StaticBodyConfig = subElement;
|
||||
break;
|
||||
case "aitarget":
|
||||
aiTarget = new AITarget(this, subElement);
|
||||
aiTarget.SoundRange = aiTarget.MinSoundRange;
|
||||
aiTarget.SightRange = aiTarget.MinSightRange;
|
||||
break;
|
||||
default:
|
||||
ItemComponent ic = ItemComponent.Load(subElement, this, itemPrefab.ConfigFile);
|
||||
@@ -674,9 +694,6 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
InitProjSpecific();
|
||||
|
||||
InsertToList();
|
||||
ItemList.Add(this);
|
||||
|
||||
if (callOnItemLoaded)
|
||||
{
|
||||
@@ -686,6 +703,9 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
InsertToList();
|
||||
ItemList.Add(this);
|
||||
|
||||
DebugConsole.Log("Created " + Name + " (" + ID + ")");
|
||||
}
|
||||
|
||||
@@ -988,7 +1008,24 @@ namespace Barotrauma
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
private 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;
|
||||
}
|
||||
|
||||
public void ApplyStatusEffects(ActionType type, float deltaTime, Character character = null, Limb limb = null, bool isNetworkEvent = false)
|
||||
{
|
||||
if (!hasStatusEffectsOfType[(int)type]) { return; }
|
||||
@@ -1103,6 +1140,7 @@ namespace Barotrauma
|
||||
|
||||
public override void Update(float deltaTime, Camera cam)
|
||||
{
|
||||
base.Update(deltaTime, cam);
|
||||
//aitarget goes silent/invisible if the components don't keep it active
|
||||
if (aiTarget != null)
|
||||
{
|
||||
@@ -1131,7 +1169,11 @@ namespace Barotrauma
|
||||
|
||||
foreach (ItemComponent ic in components)
|
||||
{
|
||||
if (ic.Parent != null) ic.IsActive = ic.Parent.IsActive;
|
||||
if (ic.Parent != null) { ic.IsActive = ic.Parent.IsActive; }
|
||||
if (ic.IsActiveConditionals != null)
|
||||
{
|
||||
ic.IsActive = ic.IsActiveConditionals.All(conditional => ConditionalMatches(conditional));
|
||||
}
|
||||
|
||||
#if CLIENT
|
||||
if (!ic.WasUsed)
|
||||
@@ -1827,7 +1869,7 @@ namespace Barotrauma
|
||||
return allProperties;
|
||||
}
|
||||
|
||||
private void WritePropertyChange(NetBuffer msg, object[] extraData, bool inGameEditableOnly)
|
||||
private void WritePropertyChange(IWriteMessage msg, object[] extraData, bool inGameEditableOnly)
|
||||
{
|
||||
var allProperties = inGameEditableOnly ? GetProperties<InGameEditable>() : GetProperties<Editable>();
|
||||
SerializableProperty property = extraData[1] as SerializableProperty;
|
||||
@@ -1836,7 +1878,7 @@ namespace Barotrauma
|
||||
var propertyOwner = allProperties.Find(p => p.Second == property);
|
||||
if (allProperties.Count > 1)
|
||||
{
|
||||
msg.WriteRangedInteger(0, allProperties.Count - 1, allProperties.FindIndex(p => p.Second == property));
|
||||
msg.WriteRangedIntegerDeprecated(0, allProperties.Count - 1, allProperties.FindIndex(p => p.Second == property));
|
||||
}
|
||||
|
||||
object value = property.GetValue(propertyOwner.First);
|
||||
@@ -1908,7 +1950,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
private void ReadPropertyChange(NetBuffer msg, bool inGameEditableOnly, Client sender = null)
|
||||
private void ReadPropertyChange(IReadMessage msg, bool inGameEditableOnly, Client sender = null)
|
||||
{
|
||||
var allProperties = inGameEditableOnly ? GetProperties<InGameEditable>() : GetProperties<Editable>();
|
||||
if (allProperties.Count == 0) { return; }
|
||||
@@ -1940,7 +1982,7 @@ namespace Barotrauma
|
||||
}
|
||||
else if (type == typeof(float))
|
||||
{
|
||||
float val = msg.ReadFloat();
|
||||
float val = msg.ReadSingle();
|
||||
if (allowEditing) property.TrySetValue(parentObject, val);
|
||||
}
|
||||
else if (type == typeof(int))
|
||||
@@ -1960,17 +2002,17 @@ namespace Barotrauma
|
||||
}
|
||||
else if (type == typeof(Vector2))
|
||||
{
|
||||
Vector2 val = new Vector2(msg.ReadFloat(), msg.ReadFloat());
|
||||
Vector2 val = new Vector2(msg.ReadSingle(), msg.ReadSingle());
|
||||
if (allowEditing) property.TrySetValue(parentObject, val);
|
||||
}
|
||||
else if (type == typeof(Vector3))
|
||||
{
|
||||
Vector3 val = new Vector3(msg.ReadFloat(), msg.ReadFloat(), msg.ReadFloat());
|
||||
Vector3 val = new Vector3(msg.ReadSingle(), msg.ReadSingle(), msg.ReadSingle());
|
||||
if (allowEditing) property.TrySetValue(parentObject, val);
|
||||
}
|
||||
else if (type == typeof(Vector4))
|
||||
{
|
||||
Vector4 val = new Vector4(msg.ReadFloat(), msg.ReadFloat(), msg.ReadFloat(), msg.ReadFloat());
|
||||
Vector4 val = new Vector4(msg.ReadSingle(), msg.ReadSingle(), msg.ReadSingle(), msg.ReadSingle());
|
||||
if (allowEditing) property.TrySetValue(parentObject, val);
|
||||
}
|
||||
else if (type == typeof(Point))
|
||||
@@ -2038,7 +2080,7 @@ namespace Barotrauma
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
Rectangle rect = element.GetAttributeRect("rect", Rectangle.Empty);
|
||||
if (rect.Width == 0 && rect.Height == 0)
|
||||
{
|
||||
@@ -2090,7 +2132,7 @@ namespace Barotrauma
|
||||
foreach (XElement subElement in element.Elements())
|
||||
{
|
||||
ItemComponent component = unloadedComponents.Find(x => x.Name == subElement.Name.ToString());
|
||||
if (component == null) continue;
|
||||
if (component == null) { continue; }
|
||||
|
||||
component.Load(subElement);
|
||||
unloadedComponents.Remove(component);
|
||||
@@ -2104,6 +2146,11 @@ namespace Barotrauma
|
||||
|
||||
item.SetActiveSprite();
|
||||
|
||||
if (submarine?.GameVersion != null)
|
||||
{
|
||||
SerializableProperty.UpgradeGameVersion(item, item.Prefab.ConfigElement, submarine.GameVersion);
|
||||
}
|
||||
|
||||
foreach (ItemComponent component in item.components)
|
||||
{
|
||||
component.OnItemLoaded();
|
||||
@@ -2164,6 +2211,7 @@ namespace Barotrauma
|
||||
SerializableProperties = SerializableProperty.DeserializeProperties(this, Prefab.ConfigElement);
|
||||
Sprite.ReloadXML();
|
||||
SpriteDepth = Sprite.Depth;
|
||||
condition = Prefab.Health;
|
||||
components.ForEach(c => c.Reset());
|
||||
}
|
||||
|
||||
@@ -2249,4 +2297,4 @@ namespace Barotrauma
|
||||
|
||||
partial void RemoveProjSpecific();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using Barotrauma.Networking;
|
||||
using FarseerPhysics;
|
||||
using FarseerPhysics.Dynamics;
|
||||
using Lidgren.Network;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -229,7 +228,13 @@ namespace Barotrauma
|
||||
|
||||
surface = rect.Y - rect.Height;
|
||||
|
||||
aiTarget = new AITarget(this);
|
||||
aiTarget = new AITarget(this)
|
||||
{
|
||||
MinSightRange = 2000,
|
||||
MaxSightRange = 5000,
|
||||
MaxSoundRange = 5000,
|
||||
SoundRange = 0
|
||||
};
|
||||
|
||||
hullList.Add(this);
|
||||
|
||||
@@ -418,13 +423,14 @@ namespace Barotrauma
|
||||
|
||||
public override void Update(float deltaTime, Camera cam)
|
||||
{
|
||||
base.Update(deltaTime, cam);
|
||||
UpdateProjSpecific(deltaTime, cam);
|
||||
|
||||
Oxygen -= OxygenDeteriorationSpeed * deltaTime;
|
||||
|
||||
FireSource.UpdateAll(FireSources, deltaTime);
|
||||
|
||||
aiTarget.SightRange = Submarine == null ? 0.0f : Math.Max(Submarine.Velocity.Length() * 2000.0f, AITarget.StaticSightRange);
|
||||
aiTarget.SightRange = Submarine == null ? aiTarget.MinSightRange : Submarine.Velocity.Length() / 2 * aiTarget.MaxSightRange;
|
||||
aiTarget.SoundRange -= deltaTime * 1000.0f;
|
||||
|
||||
if (!update)
|
||||
|
||||
@@ -5,7 +5,6 @@ using Barotrauma.RuinGeneration;
|
||||
using FarseerPhysics;
|
||||
using FarseerPhysics.Dynamics;
|
||||
using FarseerPhysics.Factories;
|
||||
using Lidgren.Network;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -1673,7 +1672,7 @@ namespace Barotrauma
|
||||
loaded = null;
|
||||
}
|
||||
|
||||
public void ServerWrite(NetBuffer msg, Client c, object[] extraData = null)
|
||||
public void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
|
||||
{
|
||||
foreach (LevelWall levelWall in extraWalls)
|
||||
{
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using Barotrauma.Networking;
|
||||
using FarseerPhysics;
|
||||
using Lidgren.Network;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -122,7 +121,7 @@ namespace Barotrauma
|
||||
return "LevelObject (" + ActivePrefab.Name + ")";
|
||||
}
|
||||
|
||||
public void ServerWrite(NetBuffer msg, Client c)
|
||||
public void ServerWrite(IWriteMessage msg, Client c)
|
||||
{
|
||||
for (int j = 0; j < Triggers.Count; j++)
|
||||
{
|
||||
|
||||
@@ -3,7 +3,6 @@ using Barotrauma.Particles;
|
||||
#endif
|
||||
using Barotrauma.Networking;
|
||||
using FarseerPhysics;
|
||||
using Lidgren.Network;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -407,10 +406,10 @@ namespace Barotrauma
|
||||
|
||||
partial void RemoveProjSpecific();
|
||||
|
||||
public void ServerWrite(NetBuffer msg, Client c, object[] extraData = null)
|
||||
public void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
|
||||
{
|
||||
LevelObject obj = extraData[0] as LevelObject;
|
||||
msg.WriteRangedInteger(0, objects.Count, objects.IndexOf(obj));
|
||||
msg.WriteRangedIntegerDeprecated(0, objects.Count, objects.IndexOf(obj));
|
||||
obj.ServerWrite(msg, c);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
using FarseerPhysics;
|
||||
using FarseerPhysics.Dynamics;
|
||||
using FarseerPhysics.Dynamics.Contacts;
|
||||
using Lidgren.Network;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -598,7 +597,7 @@ namespace Barotrauma
|
||||
return vel.ClampLength(ConvertUnits.ToDisplayUnits(ForceVelocityLimit)) * currentForceFluctuation;
|
||||
}
|
||||
|
||||
public void ServerWrite(NetBuffer msg, Client c)
|
||||
public void ServerWrite(IWriteMessage msg, Client c)
|
||||
{
|
||||
if (ForceFluctuationStrength > 0.0f)
|
||||
{
|
||||
|
||||
@@ -339,6 +339,11 @@ namespace Barotrauma
|
||||
hull.Update(deltaTime, cam);
|
||||
}
|
||||
|
||||
foreach (Structure structure in Structure.WallList)
|
||||
{
|
||||
structure.Update(deltaTime, cam);
|
||||
}
|
||||
|
||||
foreach (Gap gap in Gap.GapList)
|
||||
{
|
||||
gap.Update(deltaTime, cam);
|
||||
|
||||
@@ -40,6 +40,18 @@ namespace Barotrauma
|
||||
get { return name; }
|
||||
}
|
||||
|
||||
public string GetItemNameTextId()
|
||||
{
|
||||
var textId = $"entityname.{Identifier}";
|
||||
return TextManager.ContainsTag(textId) ? textId : null;
|
||||
}
|
||||
|
||||
public string GetHullNameTextId()
|
||||
{
|
||||
var textId = $"roomname.{Identifier}";
|
||||
return TextManager.ContainsTag(textId) ? textId : null;
|
||||
}
|
||||
|
||||
//Used to differentiate between items when saving/loading
|
||||
//Allows changing the name of an item without breaking existing subs or having multiple items with the same name
|
||||
public string Identifier
|
||||
|
||||
@@ -4,7 +4,6 @@ using FarseerPhysics;
|
||||
using FarseerPhysics.Dynamics;
|
||||
using FarseerPhysics.Dynamics.Contacts;
|
||||
using FarseerPhysics.Factories;
|
||||
using Lidgren.Network;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
@@ -373,7 +372,12 @@ namespace Barotrauma
|
||||
// Only add ai targets automatically to submarine/outpost walls
|
||||
if (aiTarget == null && HasBody && Tags.Contains("wall") && submarine != null && !Prefab.NoAITarget)
|
||||
{
|
||||
aiTarget = new AITarget(this);
|
||||
aiTarget = new AITarget(this)
|
||||
{
|
||||
MinSightRange = 2000,
|
||||
MaxSightRange = 5000,
|
||||
MaxSoundRange = 0
|
||||
};
|
||||
}
|
||||
|
||||
InsertToList();
|
||||
@@ -460,15 +464,16 @@ namespace Barotrauma
|
||||
{
|
||||
if (IsHorizontal)
|
||||
{
|
||||
xsections = (int)Math.Ceiling((float)rect.Width / WallSectionSize);
|
||||
//equivalent to (int)Math.Ceiling((double)rect.Width / WallSectionSize) without the potential for floating point indeterminism
|
||||
xsections = (rect.Width + WallSectionSize - 1) / WallSectionSize;
|
||||
Sections = new WallSection[xsections];
|
||||
width = (int)WallSectionSize;
|
||||
width = WallSectionSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
ysections = (int)Math.Ceiling((float)rect.Height / WallSectionSize);
|
||||
ysections = (rect.Height + WallSectionSize - 1) / WallSectionSize;
|
||||
Sections = new WallSection[ysections];
|
||||
height = (int)WallSectionSize;
|
||||
height = WallSectionSize;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1184,21 +1189,32 @@ namespace Barotrauma
|
||||
ID = (ushort)int.Parse(element.Attribute("ID").Value)
|
||||
};
|
||||
|
||||
SerializableProperty.DeserializeProperties(s, element);
|
||||
|
||||
foreach (XElement subElement in element.Elements())
|
||||
{
|
||||
switch (subElement.Name.ToString())
|
||||
{
|
||||
case "section":
|
||||
int index = subElement.GetAttributeInt("i", -1);
|
||||
if (index == -1) continue;
|
||||
s.Sections[index].damage = subElement.GetAttributeFloat("damage", 0.0f);
|
||||
if (index == -1) { continue; }
|
||||
|
||||
if (index < 0 || index >= s.SectionCount)
|
||||
{
|
||||
string errorMsg = $"Error while loading structure \"{s.Name}\". Section damage index out of bounds. Index: {index}, section count: {s.SectionCount}.";
|
||||
DebugConsole.ThrowError(errorMsg);
|
||||
GameAnalyticsManager.AddErrorEventOnce("Structure.Load:SectionIndexOutOfBounds", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
||||
}
|
||||
else
|
||||
{
|
||||
s.Sections[index].damage = subElement.GetAttributeFloat("damage", 0.0f);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (element.GetAttributeBool("flippedx", false)) s.FlipX(false);
|
||||
if (element.GetAttributeBool("flippedy", false)) s.FlipY(false);
|
||||
SerializableProperty.DeserializeProperties(s, element);
|
||||
|
||||
//structures with a body drop a shadow by default
|
||||
if (element.Attribute("usedropshadow") == null)
|
||||
@@ -1277,5 +1293,14 @@ namespace Barotrauma
|
||||
{
|
||||
SerializableProperties = SerializableProperty.DeserializeProperties(this, Prefab.ConfigElement);
|
||||
}
|
||||
|
||||
public override void Update(float deltaTime, Camera cam)
|
||||
{
|
||||
base.Update(deltaTime, cam);
|
||||
if (aiTarget != null)
|
||||
{
|
||||
aiTarget.SightRange = Submarine == null ? aiTarget.MinSightRange : Submarine.Velocity.Length() / 2 * aiTarget.MaxSightRange;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ using Barotrauma.Networking;
|
||||
using Barotrauma.RuinGeneration;
|
||||
using FarseerPhysics;
|
||||
using FarseerPhysics.Dynamics;
|
||||
using Lidgren.Network;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -1143,7 +1142,6 @@ namespace Barotrauma
|
||||
savedSubmarines.Add(sub);
|
||||
}
|
||||
|
||||
|
||||
public static void RefreshSavedSub(string filePath)
|
||||
{
|
||||
string fullPath = Path.GetFullPath(filePath);
|
||||
@@ -1154,12 +1152,15 @@ namespace Barotrauma
|
||||
savedSubmarines[i].Dispose();
|
||||
}
|
||||
}
|
||||
var sub = new Submarine(filePath);
|
||||
if (!sub.IsFileCorrupted)
|
||||
if (File.Exists(filePath))
|
||||
{
|
||||
savedSubmarines.Add(sub);
|
||||
var sub = new Submarine(filePath);
|
||||
if (!sub.IsFileCorrupted)
|
||||
{
|
||||
savedSubmarines.Add(sub);
|
||||
}
|
||||
savedSubmarines = savedSubmarines.OrderBy(s => s.filePath ?? "").ToList();
|
||||
}
|
||||
savedSubmarines = savedSubmarines.OrderBy(s => s.filePath ?? "").ToList();
|
||||
}
|
||||
|
||||
public static void RefreshSavedSubs()
|
||||
@@ -1210,6 +1211,15 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
var contentPackageSubs = ContentPackage.GetFilesOfType(GameMain.Config.SelectedContentPackages, ContentType.Submarine);
|
||||
foreach (string subPath in contentPackageSubs)
|
||||
{
|
||||
if (!filePaths.Any(fp => Path.GetFullPath(fp) == Path.GetFullPath(subPath)))
|
||||
{
|
||||
filePaths.Add(subPath);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (string path in filePaths)
|
||||
{
|
||||
var sub = new Submarine(path);
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Barotrauma.Items.Components;
|
||||
using Lidgren.Network;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Linq;
|
||||
@@ -7,9 +6,9 @@ using System.Text;
|
||||
|
||||
namespace Barotrauma.Networking
|
||||
{
|
||||
enum ChatMessageType
|
||||
public enum ChatMessageType
|
||||
{
|
||||
Default, Error, Dead, Server, Radio, Private, Console, MessageBox, Order, ServerLog
|
||||
Default, Error, Dead, Server, Radio, Private, Console, MessageBox, Order, ServerLog, ServerMessageBox
|
||||
}
|
||||
|
||||
partial class ChatMessage
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using Lidgren.Network;
|
||||
using Lidgren.Network;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -12,7 +12,8 @@ namespace Barotrauma.Networking
|
||||
|
||||
public string Name;
|
||||
public byte ID;
|
||||
|
||||
public UInt64 SteamID;
|
||||
|
||||
public Character.TeamType TeamID;
|
||||
|
||||
private Character character;
|
||||
@@ -38,6 +39,12 @@ namespace Barotrauma.Networking
|
||||
HasSpawned = true;
|
||||
#if CLIENT
|
||||
GameMain.GameSession?.CrewManager?.SetPlayerVoiceIconState(this, muted, mutedLocally);
|
||||
|
||||
if (character == GameMain.Client.Character && GameMain.Client.SpawnAsTraitor)
|
||||
{
|
||||
character.IsTraitor = true;
|
||||
character.TraitorCurrentObjective = GameMain.Client.TraitorFirstObjective;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -179,7 +186,7 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
|
||||
public void WritePermissions(NetBuffer msg)
|
||||
public void WritePermissions(IWriteMessage msg)
|
||||
{
|
||||
msg.Write(ID);
|
||||
msg.Write((UInt16)Permissions);
|
||||
@@ -192,7 +199,7 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
}
|
||||
public static void ReadPermissions(NetBuffer inc, out ClientPermissions permissions, out List<DebugConsole.Command> permittedCommands)
|
||||
public static void ReadPermissions(IReadMessage inc, out ClientPermissions permissions, out List<DebugConsole.Command> permittedCommands)
|
||||
{
|
||||
UInt16 permissionsInt = inc.ReadUInt16();
|
||||
|
||||
@@ -221,7 +228,7 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
|
||||
public void ReadPermissions(NetIncomingMessage inc)
|
||||
public void ReadPermissions(IReadMessage inc)
|
||||
{
|
||||
ClientPermissions permissions = ClientPermissions.None;
|
||||
List<DebugConsole.Command> permittedCommands = new List<DebugConsole.Command>();
|
||||
|
||||
@@ -7,7 +7,7 @@ using System.Xml.Linq;
|
||||
namespace Barotrauma.Networking
|
||||
{
|
||||
[Flags]
|
||||
enum ClientPermissions
|
||||
public enum ClientPermissions
|
||||
{
|
||||
None = 0x0,
|
||||
ManageRound = 0x1,
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
using Lidgren.Network;
|
||||
|
||||
namespace Barotrauma.Networking
|
||||
namespace Barotrauma.Networking
|
||||
{
|
||||
interface INetSerializable { }
|
||||
|
||||
@@ -10,10 +8,10 @@ namespace Barotrauma.Networking
|
||||
interface IClientSerializable : INetSerializable
|
||||
{
|
||||
#if CLIENT
|
||||
void ClientWrite(NetBuffer msg, object[] extraData = null);
|
||||
void ClientWrite(IWriteMessage msg, object[] extraData = null);
|
||||
#endif
|
||||
#if SERVER
|
||||
void ServerRead(ClientNetObject type, NetBuffer msg, Client c);
|
||||
void ServerRead(ClientNetObject type, IReadMessage msg, Client c);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -23,10 +21,10 @@ namespace Barotrauma.Networking
|
||||
interface IServerSerializable : INetSerializable
|
||||
{
|
||||
#if SERVER
|
||||
void ServerWrite(NetBuffer msg, Client c, object[] extraData = null);
|
||||
void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null);
|
||||
#endif
|
||||
#if CLIENT
|
||||
void ClientRead(ServerNetObject type, NetBuffer msg, float sendingTime);
|
||||
void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,12 +53,12 @@ namespace Barotrauma
|
||||
public float ExtinguishFireKarmaIncrease { get; set; }
|
||||
|
||||
|
||||
private float allowedWireDisconnectionsPerMinute;
|
||||
[Serialize(5.0f, true)]
|
||||
public float AllowedWireDisconnectionsPerMinute
|
||||
private int allowedWireDisconnectionsPerMinute;
|
||||
[Serialize(5, true)]
|
||||
public int AllowedWireDisconnectionsPerMinute
|
||||
{
|
||||
get { return allowedWireDisconnectionsPerMinute; }
|
||||
set { allowedWireDisconnectionsPerMinute = Math.Max(0.0f, value); }
|
||||
set { allowedWireDisconnectionsPerMinute = Math.Max(0, value); }
|
||||
}
|
||||
|
||||
[Serialize(6.0f, true)]
|
||||
@@ -76,6 +76,9 @@ namespace Barotrauma
|
||||
[Serialize(1.0f, true)]
|
||||
public float KickBanThreshold { get; set; }
|
||||
|
||||
[Serialize(0, true)]
|
||||
public int KicksBeforeBan { get; set; }
|
||||
|
||||
[Serialize(10.0f, true)]
|
||||
public float KarmaNotificationInterval { get; set; }
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Lidgren.Network;
|
||||
using System;
|
||||
using System;
|
||||
|
||||
namespace Barotrauma.Networking
|
||||
{
|
||||
|
||||
+7
-8
@@ -1,5 +1,4 @@
|
||||
using Lidgren.Network;
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Barotrauma.Networking
|
||||
@@ -11,10 +10,10 @@ namespace Barotrauma.Networking
|
||||
/// <summary>
|
||||
/// Write the events to the outgoing message. The recipient parameter is only needed for ServerEntityEventManager
|
||||
/// </summary>
|
||||
protected void Write(NetOutgoingMessage msg, List<NetEntityEvent> eventsToSync, out List<NetEntityEvent> sentEvents, Client recipient = null)
|
||||
protected void Write(IWriteMessage msg, List<NetEntityEvent> eventsToSync, out List<NetEntityEvent> sentEvents, Client recipient = null)
|
||||
{
|
||||
//write into a temporary buffer so we can write the number of events before the actual data
|
||||
NetBuffer tempBuffer = new NetBuffer();
|
||||
IWriteMessage tempBuffer = new WriteOnlyMessage();
|
||||
|
||||
sentEvents = new List<NetEntityEvent>();
|
||||
|
||||
@@ -22,7 +21,7 @@ namespace Barotrauma.Networking
|
||||
foreach (NetEntityEvent e in eventsToSync)
|
||||
{
|
||||
//write into a temporary buffer so we can write the length before the actual data
|
||||
NetBuffer tempEventBuffer = new NetBuffer();
|
||||
IWriteMessage tempEventBuffer = new WriteOnlyMessage();
|
||||
try
|
||||
{
|
||||
WriteEvent(tempEventBuffer, e, recipient);
|
||||
@@ -67,7 +66,7 @@ namespace Barotrauma.Networking
|
||||
|
||||
tempBuffer.Write(e.EntityID);
|
||||
tempBuffer.Write((byte)tempEventBuffer.LengthBytes);
|
||||
tempBuffer.Write(tempEventBuffer);
|
||||
tempBuffer.Write(tempEventBuffer.Buffer, 0, tempEventBuffer.LengthBytes);
|
||||
tempBuffer.WritePadBits();
|
||||
sentEvents.Add(e);
|
||||
|
||||
@@ -78,10 +77,10 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
msg.Write(eventsToSync[0].ID);
|
||||
msg.Write((byte)eventCount);
|
||||
msg.Write(tempBuffer);
|
||||
msg.Write(tempBuffer.Buffer, 0, tempBuffer.LengthBytes);
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void WriteEvent(NetBuffer buffer, NetEntityEvent entityEvent, Client recipient = null);
|
||||
protected abstract void WriteEvent(IWriteMessage buffer, NetEntityEvent entityEvent, Client recipient = null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Barotrauma.Items.Components;
|
||||
using Lidgren.Network;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -9,9 +8,6 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
enum ClientPacketHeader
|
||||
{
|
||||
REQUEST_AUTH, //ask the server if a password is needed, if so we'll get nonce for encryption
|
||||
REQUEST_STEAMAUTH, //the same as REQUEST_AUTH, but in addition we want to authenticate the player's Steam ID
|
||||
REQUEST_INIT, //ask the server to give you initialization
|
||||
UPDATE_LOBBY, //update state in lobby
|
||||
UPDATE_INGAME, //update state ingame
|
||||
|
||||
@@ -64,7 +60,9 @@ namespace Barotrauma.Networking
|
||||
|
||||
QUERY_STARTGAME, //ask the clients whether they're ready to start
|
||||
STARTGAME, //start a new round
|
||||
ENDGAME
|
||||
ENDGAME,
|
||||
|
||||
TRAITOR_MESSAGE
|
||||
}
|
||||
enum ServerNetObject
|
||||
{
|
||||
@@ -78,6 +76,14 @@ namespace Barotrauma.Networking
|
||||
ENTITY_EVENT_INITIAL,
|
||||
}
|
||||
|
||||
enum TraitorMessageType
|
||||
{
|
||||
Server,
|
||||
ServerMessageBox,
|
||||
Objective,
|
||||
Console
|
||||
}
|
||||
|
||||
enum VoteType
|
||||
{
|
||||
Unknown,
|
||||
@@ -94,6 +100,7 @@ namespace Barotrauma.Networking
|
||||
Banned,
|
||||
Kicked,
|
||||
ServerShutdown,
|
||||
ServerCrashed,
|
||||
ServerFull,
|
||||
AuthenticationRequired,
|
||||
SteamAuthenticationRequired,
|
||||
@@ -132,13 +139,7 @@ namespace Barotrauma.Networking
|
||||
#if DEBUG
|
||||
public Dictionary<string, long> messageCount = new Dictionary<string, long>();
|
||||
#endif
|
||||
|
||||
public NetPeer NetPeer
|
||||
{
|
||||
get;
|
||||
protected set;
|
||||
}
|
||||
|
||||
|
||||
protected string name;
|
||||
|
||||
protected ServerSettings serverSettings;
|
||||
@@ -154,12 +155,6 @@ namespace Barotrauma.Networking
|
||||
|
||||
public bool ShowNetStats;
|
||||
|
||||
public int Port
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public int TickRate
|
||||
{
|
||||
get { return serverSettings.TickRate; }
|
||||
@@ -205,13 +200,7 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
get { return serverSettings; }
|
||||
}
|
||||
|
||||
public NetPeerConfiguration NetPeerConfiguration
|
||||
{
|
||||
get;
|
||||
protected set;
|
||||
}
|
||||
|
||||
|
||||
public bool CanUseRadio(Character sender)
|
||||
{
|
||||
if (sender == null) return false;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Lidgren.Network;
|
||||
|
||||
namespace Barotrauma.Networking
|
||||
{
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
using System;
|
||||
|
||||
namespace Barotrauma.Networking
|
||||
{
|
||||
public enum DeliveryMethod : byte
|
||||
{
|
||||
Unreliable = 0x0,
|
||||
Reliable = 0x1,
|
||||
ReliableOrdered = 0x2
|
||||
}
|
||||
|
||||
public enum ConnectionInitialization : byte
|
||||
{
|
||||
//used by all peer implementations
|
||||
SteamTicketAndVersion = 0x1,
|
||||
Password = 0x2,
|
||||
Success = 0x0,
|
||||
|
||||
//used only by SteamP2P implementations
|
||||
ConnectionStarted = 0x3
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum PacketHeader : byte
|
||||
{
|
||||
//used by all peer implementations
|
||||
None = 0x0,
|
||||
IsCompressed = 0x1,
|
||||
IsConnectionInitializationStep = 0x2,
|
||||
|
||||
//used only by SteamP2P implementations
|
||||
IsDisconnectMessage = 0x4,
|
||||
IsServerMessage = 0x8,
|
||||
IsHeartbeatMessage = 0x10
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Barotrauma.Networking
|
||||
{
|
||||
public interface IReadMessage
|
||||
{
|
||||
bool ReadBoolean();
|
||||
void ReadPadBits();
|
||||
byte ReadByte();
|
||||
UInt16 ReadUInt16();
|
||||
Int16 ReadInt16();
|
||||
UInt32 ReadUInt32();
|
||||
Int32 ReadInt32();
|
||||
UInt64 ReadUInt64();
|
||||
Int64 ReadInt64();
|
||||
Single ReadSingle();
|
||||
Double ReadDouble();
|
||||
UInt32 ReadVariableUInt32();
|
||||
String ReadString();
|
||||
int ReadRangedInteger(int min, int max);
|
||||
Single ReadRangedSingle(Single min, Single max, int bitCount);
|
||||
byte[] ReadBytes(int numberOfBytes);
|
||||
|
||||
int BitPosition { get; set; }
|
||||
int BytePosition { get; }
|
||||
byte[] Buffer { get; }
|
||||
int LengthBits { get; set; }
|
||||
int LengthBytes { get; }
|
||||
|
||||
NetworkConnection Sender { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
using System;
|
||||
|
||||
namespace Barotrauma.Networking
|
||||
{
|
||||
public interface IWriteMessage
|
||||
{
|
||||
void Write(bool val);
|
||||
void WritePadBits();
|
||||
void Write(byte val);
|
||||
void Write(Int16 val);
|
||||
void Write(UInt16 val);
|
||||
void Write(Int32 val);
|
||||
void Write(UInt32 val);
|
||||
void Write(Int64 val);
|
||||
void Write(UInt64 val);
|
||||
void Write(Single val);
|
||||
void Write(Double val);
|
||||
void WriteVariableUInt32(UInt32 val);
|
||||
void Write(string val);
|
||||
void WriteRangedIntegerDeprecated(int min, int max, int val); //TODO: remove this, val should be first parameter >:(
|
||||
void WriteRangedInteger(int val, int min, int max);
|
||||
void WriteRangedSingle(Single val, Single min, Single max, int bitCount);
|
||||
void Write(byte[] val, int startIndex, int length);
|
||||
|
||||
void PrepareForSending(ref byte[] outBuf, out bool isCompressed, out int outLength);
|
||||
|
||||
int BitPosition { get; set; }
|
||||
int BytePosition { get; }
|
||||
byte[] Buffer { get; }
|
||||
int LengthBits { get; set; }
|
||||
int LengthBytes { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,955 @@
|
||||
using Lidgren.Network;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace Barotrauma.Networking
|
||||
{
|
||||
public static class MsgConstants
|
||||
{
|
||||
public const int MTU = 1200;
|
||||
public const int CompressionThreshold = 1000;
|
||||
public const int InitialBufferSize = 256;
|
||||
public const int BufferOverAllocateAmount = 4;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Utility struct for writing Singles
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Explicit)]
|
||||
public struct SingleUIntUnion
|
||||
{
|
||||
/// <summary>
|
||||
/// Value as a 32 bit float
|
||||
/// </summary>
|
||||
[FieldOffset(0)]
|
||||
public float SingleValue;
|
||||
|
||||
/// <summary>
|
||||
/// Value as an unsigned 32 bit integer
|
||||
/// </summary>
|
||||
[FieldOffset(0)]
|
||||
public uint UIntValue;
|
||||
}
|
||||
|
||||
internal static class MsgWriter
|
||||
{
|
||||
internal static void Write(ref byte[] buf, ref int bitPos, bool val)
|
||||
{
|
||||
#if DEBUG
|
||||
int resetPos = bitPos;
|
||||
#endif
|
||||
|
||||
EnsureBufferSize(ref buf, bitPos + 1);
|
||||
|
||||
int bytePos = bitPos / 8;
|
||||
int bitOffset = bitPos % 8;
|
||||
byte bitFlag = (byte)(1 << bitOffset);
|
||||
byte bitMask = (byte)((~bitFlag) & 0xff);
|
||||
buf[bytePos] &= bitMask;
|
||||
if (val) buf[bytePos] |= bitFlag;
|
||||
bitPos++;
|
||||
|
||||
#if DEBUG
|
||||
bool testVal = MsgReader.ReadBoolean(buf, ref resetPos);
|
||||
if (testVal != val || resetPos != bitPos)
|
||||
{
|
||||
DebugConsole.ThrowError("Boolean written incorrectly! " + testVal + ", " + val + "; " + resetPos + ", " + bitPos);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
internal static void WritePadBits(ref byte[] buf, ref int bitPos)
|
||||
{
|
||||
int bitOffset = bitPos % 8;
|
||||
bitPos += ((8 - bitOffset) % 8);
|
||||
EnsureBufferSize(ref buf, bitPos);
|
||||
}
|
||||
|
||||
internal static void Write(ref byte[] buf, ref int bitPos, byte val)
|
||||
{
|
||||
EnsureBufferSize(ref buf, bitPos + 8);
|
||||
NetBitWriter.WriteByte(val, 8, buf, bitPos);
|
||||
bitPos += 8;
|
||||
}
|
||||
|
||||
internal static void Write(ref byte[] buf, ref int bitPos, UInt16 val)
|
||||
{
|
||||
EnsureBufferSize(ref buf, bitPos + 16);
|
||||
NetBitWriter.WriteUInt16(val, 16, buf, bitPos);
|
||||
bitPos += 16;
|
||||
}
|
||||
|
||||
internal static void Write(ref byte[] buf, ref int bitPos, Int16 val)
|
||||
{
|
||||
EnsureBufferSize(ref buf, bitPos + 16);
|
||||
NetBitWriter.WriteUInt16((UInt16)val, 16, buf, bitPos);
|
||||
bitPos += 16;
|
||||
}
|
||||
|
||||
internal static void Write(ref byte[] buf, ref int bitPos, UInt32 val)
|
||||
{
|
||||
EnsureBufferSize(ref buf, bitPos + 32);
|
||||
NetBitWriter.WriteUInt32(val, 32, buf, bitPos);
|
||||
bitPos += 32;
|
||||
}
|
||||
|
||||
internal static void Write(ref byte[] buf, ref int bitPos, Int32 val)
|
||||
{
|
||||
EnsureBufferSize(ref buf, bitPos + 32);
|
||||
NetBitWriter.WriteUInt32((UInt32)val, 32, buf, bitPos);
|
||||
bitPos += 32;
|
||||
}
|
||||
|
||||
internal static void Write(ref byte[] buf, ref int bitPos, UInt64 val)
|
||||
{
|
||||
EnsureBufferSize(ref buf, bitPos + 64);
|
||||
NetBitWriter.WriteUInt64(val, 64, buf, bitPos);
|
||||
bitPos += 64;
|
||||
}
|
||||
|
||||
internal static void Write(ref byte[] buf, ref int bitPos, Int64 val)
|
||||
{
|
||||
EnsureBufferSize(ref buf, bitPos + 64);
|
||||
NetBitWriter.WriteUInt64((UInt64)val, 64, buf, bitPos);
|
||||
bitPos += 64;
|
||||
}
|
||||
|
||||
internal static void Write(ref byte[] buf, ref int bitPos, Single val)
|
||||
{
|
||||
// Use union to avoid BitConverter.GetBytes() which allocates memory on the heap
|
||||
SingleUIntUnion su;
|
||||
su.UIntValue = 0; // must initialize every member of the union to avoid warning
|
||||
su.SingleValue = val;
|
||||
|
||||
EnsureBufferSize(ref buf, bitPos + 32);
|
||||
|
||||
NetBitWriter.WriteUInt32(su.UIntValue, 32, buf, bitPos);
|
||||
bitPos += 32;
|
||||
}
|
||||
|
||||
internal static void Write(ref byte[] buf, ref int bitPos, Double val)
|
||||
{
|
||||
EnsureBufferSize(ref buf, bitPos + 64);
|
||||
|
||||
byte[] bytes = BitConverter.GetBytes(val);
|
||||
WriteBytes(ref buf, ref bitPos, bytes, 0, bytes.Length);
|
||||
bitPos += 64;
|
||||
}
|
||||
internal static void Write(ref byte[] buf, ref int bitPos, string val)
|
||||
{
|
||||
if (string.IsNullOrEmpty(val))
|
||||
{
|
||||
WriteVariableUInt32(ref buf, ref bitPos, (uint)0);
|
||||
return;
|
||||
}
|
||||
|
||||
byte[] bytes = Encoding.UTF8.GetBytes(val);
|
||||
WriteVariableUInt32(ref buf, ref bitPos, (uint)bytes.Length);
|
||||
WriteBytes(ref buf, ref bitPos, bytes, 0, bytes.Length);
|
||||
}
|
||||
|
||||
internal static int WriteVariableUInt32(ref byte[] buf, ref int bitPos, uint value)
|
||||
{
|
||||
int retval = 1;
|
||||
uint num1 = (uint)value;
|
||||
while (num1 >= 0x80)
|
||||
{
|
||||
Write(ref buf, ref bitPos, (byte)(num1 | 0x80));
|
||||
num1 = num1 >> 7;
|
||||
retval++;
|
||||
}
|
||||
Write(ref buf, ref bitPos, (byte)num1);
|
||||
return retval;
|
||||
}
|
||||
|
||||
internal static void WriteRangedInteger(ref byte[] buf, ref int bitPos, int val, int min, int max)
|
||||
{
|
||||
uint range = (uint)(max - min);
|
||||
int numberOfBits = NetUtility.BitsToHoldUInt(range);
|
||||
|
||||
EnsureBufferSize(ref buf, bitPos + numberOfBits);
|
||||
|
||||
uint rvalue = (uint)(val - min);
|
||||
NetBitWriter.WriteUInt32(rvalue, numberOfBits, buf, bitPos);
|
||||
bitPos += numberOfBits;
|
||||
}
|
||||
|
||||
internal static void WriteRangedSingle(ref byte[] buf, ref int bitPos, Single val, Single min, Single max, int numberOfBits)
|
||||
{
|
||||
float range = max - min;
|
||||
float unit = ((val - min) / range);
|
||||
int maxVal = (1 << numberOfBits) - 1;
|
||||
|
||||
EnsureBufferSize(ref buf, bitPos + numberOfBits);
|
||||
|
||||
NetBitWriter.WriteUInt32((UInt32)((float)maxVal * unit), numberOfBits, buf, bitPos);
|
||||
bitPos += numberOfBits;
|
||||
}
|
||||
|
||||
internal static void WriteBytes(ref byte[] buf, ref int bitPos, byte[] val, int pos, int length)
|
||||
{
|
||||
EnsureBufferSize(ref buf, bitPos + length * 8);
|
||||
NetBitWriter.WriteBytes(val, pos, length, buf, bitPos);
|
||||
bitPos += length * 8;
|
||||
}
|
||||
|
||||
internal static void EnsureBufferSize(ref byte[] buf, int numberOfBits)
|
||||
{
|
||||
int byteLen = ((numberOfBits + 7) >> 3);
|
||||
if (buf == null)
|
||||
{
|
||||
buf = new byte[byteLen + MsgConstants.BufferOverAllocateAmount];
|
||||
return;
|
||||
}
|
||||
if (buf.Length < byteLen)
|
||||
{
|
||||
Array.Resize<byte>(ref buf, byteLen + MsgConstants.BufferOverAllocateAmount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static class MsgReader
|
||||
{
|
||||
internal static bool ReadBoolean(byte[] buf, ref int bitPos)
|
||||
{
|
||||
byte retval = NetBitWriter.ReadByte(buf, 1, bitPos);
|
||||
bitPos++;
|
||||
return (retval > 0 ? true : false);
|
||||
}
|
||||
|
||||
internal static void ReadPadBits(byte[] buf, ref int bitPos)
|
||||
{
|
||||
int bitOffset = bitPos % 8;
|
||||
bitPos += (8 - bitOffset) % 8;
|
||||
}
|
||||
|
||||
internal static byte ReadByte(byte[] buf, ref int bitPos)
|
||||
{
|
||||
byte retval = NetBitWriter.ReadByte(buf, 8, bitPos);
|
||||
bitPos += 8;
|
||||
return retval;
|
||||
}
|
||||
|
||||
internal static UInt16 ReadUInt16(byte[] buf, ref int bitPos)
|
||||
{
|
||||
uint retval = NetBitWriter.ReadUInt16(buf, 16, bitPos);
|
||||
bitPos += 16;
|
||||
return (ushort)retval;
|
||||
}
|
||||
|
||||
internal static Int16 ReadInt16(byte[] buf, ref int bitPos)
|
||||
{
|
||||
return (Int16)ReadUInt16(buf, ref bitPos);
|
||||
}
|
||||
|
||||
internal static UInt32 ReadUInt32(byte[] buf, ref int bitPos)
|
||||
{
|
||||
uint retval = NetBitWriter.ReadUInt32(buf, 32, bitPos);
|
||||
bitPos += 32;
|
||||
return retval;
|
||||
}
|
||||
|
||||
internal static Int32 ReadInt32(byte[] buf, ref int bitPos)
|
||||
{
|
||||
return (Int32)ReadUInt32(buf, ref bitPos);
|
||||
}
|
||||
|
||||
internal static UInt64 ReadUInt64(byte[] buf, ref int bitPos)
|
||||
{
|
||||
ulong low = NetBitWriter.ReadUInt32(buf, 32, bitPos);
|
||||
bitPos += 32;
|
||||
ulong high = NetBitWriter.ReadUInt32(buf, 32, bitPos);
|
||||
ulong retval = low + (high << 32);
|
||||
bitPos += 32;
|
||||
return retval;
|
||||
}
|
||||
|
||||
internal static Int64 ReadInt64(byte[] buf, ref int bitPos)
|
||||
{
|
||||
return (Int64)ReadUInt64(buf, ref bitPos);
|
||||
}
|
||||
|
||||
internal static Single ReadSingle(byte[] buf, ref int bitPos)
|
||||
{
|
||||
if ((bitPos & 7) == 0) // read directly
|
||||
{
|
||||
float retval = BitConverter.ToSingle(buf, bitPos >> 3);
|
||||
bitPos += 32;
|
||||
return retval;
|
||||
}
|
||||
|
||||
byte[] bytes = ReadBytes(buf, ref bitPos, 4);
|
||||
return BitConverter.ToSingle(bytes, 0);
|
||||
}
|
||||
|
||||
internal static Double ReadDouble(byte[] buf, ref int bitPos)
|
||||
{
|
||||
if ((bitPos & 7) == 0) // read directly
|
||||
{
|
||||
// read directly
|
||||
double retval = BitConverter.ToDouble(buf, bitPos >> 3);
|
||||
bitPos += 64;
|
||||
return retval;
|
||||
}
|
||||
|
||||
byte[] bytes = ReadBytes(buf, ref bitPos, 8);
|
||||
return BitConverter.ToDouble(bytes, 0);
|
||||
}
|
||||
|
||||
internal static UInt32 ReadVariableUInt32(byte[] buf, ref int bitPos)
|
||||
{
|
||||
int bitLength = buf.Length * 8;
|
||||
|
||||
int num1 = 0;
|
||||
int num2 = 0;
|
||||
while (bitLength - bitPos >= 8)
|
||||
{
|
||||
byte num3 = ReadByte(buf, ref bitPos);
|
||||
num1 |= (num3 & 0x7f) << num2;
|
||||
num2 += 7;
|
||||
if ((num3 & 0x80) == 0)
|
||||
return (uint)num1;
|
||||
}
|
||||
|
||||
// ouch; failed to find enough bytes; malformed variable length number?
|
||||
return (uint)num1;
|
||||
}
|
||||
|
||||
internal static String ReadString(byte[] buf, ref int bitPos)
|
||||
{
|
||||
int bitLength = buf.Length * 8;
|
||||
int byteLen = (int)ReadVariableUInt32(buf, ref bitPos);
|
||||
|
||||
if (byteLen <= 0) { return String.Empty; }
|
||||
|
||||
if ((ulong)(bitLength - bitPos) < ((ulong)byteLen * 8))
|
||||
{
|
||||
// not enough data
|
||||
return null;
|
||||
}
|
||||
|
||||
if ((bitPos & 7) == 0)
|
||||
{
|
||||
// read directly
|
||||
string retval = System.Text.Encoding.UTF8.GetString(buf, bitPos >> 3, byteLen);
|
||||
bitPos += (8 * byteLen);
|
||||
return retval;
|
||||
}
|
||||
|
||||
byte[] bytes = ReadBytes(buf, ref bitPos, byteLen);
|
||||
return System.Text.Encoding.UTF8.GetString(bytes, 0, bytes.Length);
|
||||
}
|
||||
|
||||
internal static int ReadRangedInteger(byte[] buf, ref int bitPos, int min, int max)
|
||||
{
|
||||
uint range = (uint)(max - min);
|
||||
int numBits = NetUtility.BitsToHoldUInt(range);
|
||||
|
||||
uint rvalue = NetBitWriter.ReadUInt32(buf, numBits, bitPos);
|
||||
bitPos += numBits;
|
||||
|
||||
return (int)(min + rvalue);
|
||||
}
|
||||
|
||||
internal static Single ReadRangedSingle(byte[] buf, ref int bitPos, Single min, Single max, int bitCount)
|
||||
{
|
||||
int maxInt = (1 << bitCount) - 1;
|
||||
int intVal = ReadRangedInteger(buf, ref bitPos, 0, maxInt);
|
||||
Single range = max - min;
|
||||
return min + (range * ((Single)intVal) / ((Single)maxInt));
|
||||
}
|
||||
|
||||
internal static byte[] ReadBytes(byte[] buf, ref int bitPos, int numberOfBytes)
|
||||
{
|
||||
byte[] retval = new byte[numberOfBytes];
|
||||
NetBitWriter.ReadBytes(buf, numberOfBytes, bitPos, retval, 0);
|
||||
bitPos += (8 * numberOfBytes);
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
|
||||
public class WriteOnlyMessage : IWriteMessage
|
||||
{
|
||||
private byte[] buf = new byte[MsgConstants.InitialBufferSize];
|
||||
private int seekPos = 0;
|
||||
private int lengthBits = 0;
|
||||
|
||||
public int BitPosition
|
||||
{
|
||||
get
|
||||
{
|
||||
return seekPos;
|
||||
}
|
||||
set
|
||||
{
|
||||
seekPos = value;
|
||||
}
|
||||
}
|
||||
|
||||
public int BytePosition
|
||||
{
|
||||
get
|
||||
{
|
||||
return seekPos / 8;
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] Buffer
|
||||
{
|
||||
get
|
||||
{
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
|
||||
public int LengthBits
|
||||
{
|
||||
get
|
||||
{
|
||||
lengthBits = seekPos > lengthBits ? seekPos : lengthBits;
|
||||
return lengthBits;
|
||||
}
|
||||
set
|
||||
{
|
||||
lengthBits = value;
|
||||
seekPos = seekPos > lengthBits ? lengthBits : seekPos;
|
||||
}
|
||||
}
|
||||
|
||||
public int LengthBytes
|
||||
{
|
||||
get
|
||||
{
|
||||
return (LengthBits + ((8 - (LengthBits % 8)) % 8)) / 8;
|
||||
}
|
||||
}
|
||||
|
||||
public void Write(bool val)
|
||||
{
|
||||
MsgWriter.Write(ref buf, ref seekPos, val);
|
||||
}
|
||||
|
||||
public void WritePadBits()
|
||||
{
|
||||
MsgWriter.WritePadBits(ref buf, ref seekPos);
|
||||
}
|
||||
|
||||
public void Write(byte val)
|
||||
{
|
||||
MsgWriter.Write(ref buf, ref seekPos, val);
|
||||
}
|
||||
|
||||
public void Write(UInt16 val)
|
||||
{
|
||||
MsgWriter.Write(ref buf, ref seekPos, val);
|
||||
}
|
||||
|
||||
public void Write(Int16 val)
|
||||
{
|
||||
MsgWriter.Write(ref buf, ref seekPos, val);
|
||||
}
|
||||
|
||||
public void Write(UInt32 val)
|
||||
{
|
||||
MsgWriter.Write(ref buf, ref seekPos, val);
|
||||
}
|
||||
|
||||
public void Write(Int32 val)
|
||||
{
|
||||
MsgWriter.Write(ref buf, ref seekPos, val);
|
||||
}
|
||||
|
||||
public void Write(UInt64 val)
|
||||
{
|
||||
MsgWriter.Write(ref buf, ref seekPos, val);
|
||||
}
|
||||
|
||||
public void Write(Int64 val)
|
||||
{
|
||||
MsgWriter.Write(ref buf, ref seekPos, val);
|
||||
}
|
||||
|
||||
public void Write(Single val)
|
||||
{
|
||||
MsgWriter.Write(ref buf, ref seekPos, val);
|
||||
}
|
||||
|
||||
public void Write(Double val)
|
||||
{
|
||||
MsgWriter.Write(ref buf, ref seekPos, val);
|
||||
}
|
||||
|
||||
public void WriteVariableUInt32(UInt32 val)
|
||||
{
|
||||
MsgWriter.WriteVariableUInt32(ref buf, ref seekPos, val);
|
||||
}
|
||||
|
||||
public void Write(String val)
|
||||
{
|
||||
MsgWriter.Write(ref buf, ref seekPos, val);
|
||||
}
|
||||
|
||||
public void WriteRangedIntegerDeprecated(int min, int max, int val)
|
||||
{
|
||||
MsgWriter.WriteRangedInteger(ref buf, ref seekPos, val, min, max);
|
||||
}
|
||||
|
||||
public void WriteRangedInteger(int val, int min, int max)
|
||||
{
|
||||
MsgWriter.WriteRangedInteger(ref buf, ref seekPos, val, min, max);
|
||||
}
|
||||
|
||||
public void WriteRangedSingle(Single val, Single min, Single max, int bitCount)
|
||||
{
|
||||
MsgWriter.WriteRangedSingle(ref buf, ref seekPos, val, min, max, bitCount);
|
||||
}
|
||||
|
||||
public void Write(byte[] val, int startPos, int length)
|
||||
{
|
||||
MsgWriter.WriteBytes(ref buf, ref seekPos, val, startPos, length);
|
||||
}
|
||||
|
||||
public void PrepareForSending(ref byte[] outBuf, out bool isCompressed, out int length)
|
||||
{
|
||||
if (LengthBytes <= MsgConstants.CompressionThreshold)
|
||||
{
|
||||
isCompressed = false;
|
||||
if (LengthBytes > outBuf.Length) { Array.Resize(ref outBuf, LengthBytes); }
|
||||
Array.Copy(buf, outBuf, LengthBytes);
|
||||
length = LengthBytes;
|
||||
}
|
||||
else
|
||||
{
|
||||
using (MemoryStream output = new MemoryStream())
|
||||
{
|
||||
using (DeflateStream dstream = new DeflateStream(output, CompressionLevel.Fastest))
|
||||
{
|
||||
dstream.Write(buf, 0, LengthBytes);
|
||||
}
|
||||
|
||||
byte[] compressedBuf = output.ToArray();
|
||||
//don't send the data as compressed if the data takes up more space after compression
|
||||
//(which may happen when sending a sub/save file that's already been compressed with a better compression ratio)
|
||||
if (compressedBuf.Length >= outBuf.Length)
|
||||
{
|
||||
isCompressed = false;
|
||||
if (LengthBytes > outBuf.Length) { Array.Resize(ref outBuf, LengthBytes); }
|
||||
Array.Copy(buf, outBuf, LengthBytes);
|
||||
length = LengthBytes;
|
||||
}
|
||||
else
|
||||
{
|
||||
isCompressed = true;
|
||||
if (compressedBuf.Length > outBuf.Length) { Array.Resize(ref outBuf, compressedBuf.Length); }
|
||||
Array.Copy(compressedBuf, outBuf, compressedBuf.Length);
|
||||
length = compressedBuf.Length;
|
||||
DebugConsole.NewMessage("Compressed message: " + LengthBytes + " to " + length);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class ReadOnlyMessage : IReadMessage
|
||||
{
|
||||
private byte[] buf;
|
||||
private int seekPos = 0;
|
||||
private int lengthBits = 0;
|
||||
|
||||
public int BitPosition
|
||||
{
|
||||
get
|
||||
{
|
||||
return seekPos;
|
||||
}
|
||||
set
|
||||
{
|
||||
seekPos = value;
|
||||
}
|
||||
}
|
||||
|
||||
public int BytePosition
|
||||
{
|
||||
get
|
||||
{
|
||||
return seekPos / 8;
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] Buffer
|
||||
{
|
||||
get
|
||||
{
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
|
||||
public int LengthBits
|
||||
{
|
||||
get
|
||||
{
|
||||
lengthBits = seekPos > lengthBits ? seekPos : lengthBits;
|
||||
return lengthBits;
|
||||
}
|
||||
set
|
||||
{
|
||||
lengthBits = value;
|
||||
seekPos = seekPos > lengthBits ? lengthBits : seekPos;
|
||||
}
|
||||
}
|
||||
|
||||
public int LengthBytes
|
||||
{
|
||||
get
|
||||
{
|
||||
return lengthBits / 8;
|
||||
}
|
||||
}
|
||||
|
||||
public NetworkConnection Sender { get; private set; }
|
||||
|
||||
public ReadOnlyMessage(byte[] inBuf, bool isCompressed, int startPos, int inLength, NetworkConnection sender)
|
||||
{
|
||||
Sender = sender;
|
||||
if (isCompressed)
|
||||
{
|
||||
byte[] decompressedData;
|
||||
using (MemoryStream input = new MemoryStream(inBuf, startPos, inLength))
|
||||
{
|
||||
using (MemoryStream output = new MemoryStream())
|
||||
{
|
||||
using (DeflateStream dstream = new DeflateStream(input, CompressionMode.Decompress))
|
||||
{
|
||||
dstream.CopyTo(output);
|
||||
}
|
||||
decompressedData = output.ToArray();
|
||||
}
|
||||
}
|
||||
buf = new byte[decompressedData.Length];
|
||||
Array.Copy(decompressedData, 0, buf, 0, decompressedData.Length);
|
||||
lengthBits = decompressedData.Length * 8;
|
||||
DebugConsole.NewMessage("Decompressing message: " + inLength + " to " + LengthBytes);
|
||||
}
|
||||
else
|
||||
{
|
||||
buf = new byte[inBuf.Length];
|
||||
Array.Copy(inBuf, startPos, buf, 0, inLength);
|
||||
lengthBits = inLength * 8;
|
||||
}
|
||||
seekPos = 0;
|
||||
}
|
||||
|
||||
public bool ReadBoolean()
|
||||
{
|
||||
return MsgReader.ReadBoolean(buf, ref seekPos);
|
||||
}
|
||||
|
||||
public void ReadPadBits()
|
||||
{
|
||||
MsgReader.ReadPadBits(buf, ref seekPos);
|
||||
}
|
||||
|
||||
public byte ReadByte()
|
||||
{
|
||||
return MsgReader.ReadByte(buf, ref seekPos);
|
||||
}
|
||||
|
||||
public UInt16 ReadUInt16()
|
||||
{
|
||||
return MsgReader.ReadUInt16(buf, ref seekPos);
|
||||
}
|
||||
|
||||
public Int16 ReadInt16()
|
||||
{
|
||||
return MsgReader.ReadInt16(buf, ref seekPos);
|
||||
}
|
||||
|
||||
public UInt32 ReadUInt32()
|
||||
{
|
||||
return MsgReader.ReadUInt32(buf, ref seekPos);
|
||||
}
|
||||
|
||||
public Int32 ReadInt32()
|
||||
{
|
||||
return MsgReader.ReadInt32(buf, ref seekPos);
|
||||
}
|
||||
|
||||
public UInt64 ReadUInt64()
|
||||
{
|
||||
return MsgReader.ReadUInt64(buf, ref seekPos);
|
||||
}
|
||||
|
||||
public Int64 ReadInt64()
|
||||
{
|
||||
return MsgReader.ReadInt64(buf, ref seekPos);
|
||||
}
|
||||
|
||||
public Single ReadSingle()
|
||||
{
|
||||
return MsgReader.ReadSingle(buf, ref seekPos);
|
||||
}
|
||||
|
||||
public Double ReadDouble()
|
||||
{
|
||||
return MsgReader.ReadDouble(buf, ref seekPos);
|
||||
}
|
||||
|
||||
public UInt32 ReadVariableUInt32()
|
||||
{
|
||||
return MsgReader.ReadVariableUInt32(buf, ref seekPos);
|
||||
}
|
||||
|
||||
public String ReadString()
|
||||
{
|
||||
return MsgReader.ReadString(buf, ref seekPos);
|
||||
}
|
||||
|
||||
public int ReadRangedInteger(int min, int max)
|
||||
{
|
||||
return MsgReader.ReadRangedInteger(buf, ref seekPos, min, max);
|
||||
}
|
||||
|
||||
public Single ReadRangedSingle(Single min, Single max, int bitCount)
|
||||
{
|
||||
return MsgReader.ReadRangedSingle(buf, ref seekPos, min, max, bitCount);
|
||||
}
|
||||
|
||||
public byte[] ReadBytes(int numberOfBytes)
|
||||
{
|
||||
return MsgReader.ReadBytes(buf, ref seekPos, numberOfBytes);
|
||||
}
|
||||
}
|
||||
|
||||
public class ReadWriteMessage : IWriteMessage, IReadMessage
|
||||
{
|
||||
private byte[] buf = new byte[MsgConstants.InitialBufferSize];
|
||||
private int seekPos = 0;
|
||||
private int lengthBits = 0;
|
||||
|
||||
public int BitPosition
|
||||
{
|
||||
get
|
||||
{
|
||||
return seekPos;
|
||||
}
|
||||
set
|
||||
{
|
||||
seekPos = value;
|
||||
}
|
||||
}
|
||||
|
||||
public int BytePosition
|
||||
{
|
||||
get
|
||||
{
|
||||
return seekPos / 8;
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] Buffer
|
||||
{
|
||||
get
|
||||
{
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
|
||||
public int LengthBits
|
||||
{
|
||||
get
|
||||
{
|
||||
lengthBits = seekPos > lengthBits ? seekPos : lengthBits;
|
||||
return lengthBits;
|
||||
}
|
||||
set
|
||||
{
|
||||
lengthBits = value;
|
||||
seekPos = seekPos > lengthBits ? lengthBits : seekPos;
|
||||
}
|
||||
}
|
||||
|
||||
public int LengthBytes
|
||||
{
|
||||
get
|
||||
{
|
||||
return (LengthBits + ((8 - (LengthBits % 8)) % 8)) / 8;
|
||||
}
|
||||
}
|
||||
|
||||
public NetworkConnection Sender { get { return null; } }
|
||||
|
||||
public void Write(bool val)
|
||||
{
|
||||
MsgWriter.Write(ref buf, ref seekPos, val);
|
||||
}
|
||||
|
||||
public void WritePadBits()
|
||||
{
|
||||
MsgWriter.WritePadBits(ref buf, ref seekPos);
|
||||
}
|
||||
|
||||
public void Write(byte val)
|
||||
{
|
||||
MsgWriter.Write(ref buf, ref seekPos, val);
|
||||
}
|
||||
|
||||
public void Write(UInt16 val)
|
||||
{
|
||||
MsgWriter.Write(ref buf, ref seekPos, val);
|
||||
}
|
||||
|
||||
public void Write(Int16 val)
|
||||
{
|
||||
MsgWriter.Write(ref buf, ref seekPos, val);
|
||||
}
|
||||
|
||||
public void Write(UInt32 val)
|
||||
{
|
||||
MsgWriter.Write(ref buf, ref seekPos, val);
|
||||
}
|
||||
|
||||
public void Write(Int32 val)
|
||||
{
|
||||
MsgWriter.Write(ref buf, ref seekPos, val);
|
||||
}
|
||||
|
||||
public void Write(UInt64 val)
|
||||
{
|
||||
MsgWriter.Write(ref buf, ref seekPos, val);
|
||||
}
|
||||
|
||||
public void Write(Int64 val)
|
||||
{
|
||||
MsgWriter.Write(ref buf, ref seekPos, val);
|
||||
}
|
||||
|
||||
public void Write(Single val)
|
||||
{
|
||||
MsgWriter.Write(ref buf, ref seekPos, val);
|
||||
}
|
||||
|
||||
public void Write(Double val)
|
||||
{
|
||||
MsgWriter.Write(ref buf, ref seekPos, val);
|
||||
}
|
||||
|
||||
public void WriteVariableUInt32(UInt32 val)
|
||||
{
|
||||
MsgWriter.WriteVariableUInt32(ref buf, ref seekPos, val);
|
||||
}
|
||||
|
||||
public void Write(String val)
|
||||
{
|
||||
MsgWriter.Write(ref buf, ref seekPos, val);
|
||||
}
|
||||
|
||||
public void WriteRangedIntegerDeprecated(int min, int max, int val)
|
||||
{
|
||||
MsgWriter.WriteRangedInteger(ref buf, ref seekPos, val, min, max);
|
||||
}
|
||||
|
||||
public void WriteRangedInteger(int val, int min, int max)
|
||||
{
|
||||
MsgWriter.WriteRangedInteger(ref buf, ref seekPos, val, min, max);
|
||||
}
|
||||
|
||||
public void WriteRangedSingle(Single val, Single min, Single max, int bitCount)
|
||||
{
|
||||
MsgWriter.WriteRangedSingle(ref buf, ref seekPos, val, min, max, bitCount);
|
||||
}
|
||||
|
||||
public void Write(byte[] val, int startPos, int length)
|
||||
{
|
||||
MsgWriter.WriteBytes(ref buf, ref seekPos, val, startPos, length);
|
||||
}
|
||||
|
||||
public bool ReadBoolean()
|
||||
{
|
||||
return MsgReader.ReadBoolean(buf, ref seekPos);
|
||||
}
|
||||
|
||||
public void ReadPadBits()
|
||||
{
|
||||
MsgReader.ReadPadBits(buf, ref seekPos);
|
||||
}
|
||||
|
||||
public byte ReadByte()
|
||||
{
|
||||
return MsgReader.ReadByte(buf, ref seekPos);
|
||||
}
|
||||
|
||||
public UInt16 ReadUInt16()
|
||||
{
|
||||
return MsgReader.ReadUInt16(buf, ref seekPos);
|
||||
}
|
||||
|
||||
public Int16 ReadInt16()
|
||||
{
|
||||
return MsgReader.ReadInt16(buf, ref seekPos);
|
||||
}
|
||||
|
||||
public UInt32 ReadUInt32()
|
||||
{
|
||||
return MsgReader.ReadUInt32(buf, ref seekPos);
|
||||
}
|
||||
|
||||
public Int32 ReadInt32()
|
||||
{
|
||||
return MsgReader.ReadInt32(buf, ref seekPos);
|
||||
}
|
||||
|
||||
public UInt64 ReadUInt64()
|
||||
{
|
||||
return MsgReader.ReadUInt64(buf, ref seekPos);
|
||||
}
|
||||
|
||||
public Int64 ReadInt64()
|
||||
{
|
||||
return MsgReader.ReadInt64(buf, ref seekPos);
|
||||
}
|
||||
|
||||
public Single ReadSingle()
|
||||
{
|
||||
return MsgReader.ReadSingle(buf, ref seekPos);
|
||||
}
|
||||
|
||||
public Double ReadDouble()
|
||||
{
|
||||
return MsgReader.ReadDouble(buf, ref seekPos);
|
||||
}
|
||||
|
||||
public UInt32 ReadVariableUInt32()
|
||||
{
|
||||
return MsgReader.ReadVariableUInt32(buf, ref seekPos);
|
||||
}
|
||||
|
||||
public String ReadString()
|
||||
{
|
||||
return MsgReader.ReadString(buf, ref seekPos);
|
||||
}
|
||||
|
||||
public int ReadRangedInteger(int min, int max)
|
||||
{
|
||||
return MsgReader.ReadRangedInteger(buf, ref seekPos, min, max);
|
||||
}
|
||||
|
||||
public Single ReadRangedSingle(Single min, Single max, int bitCount)
|
||||
{
|
||||
return MsgReader.ReadRangedSingle(buf, ref seekPos, min, max, bitCount);
|
||||
}
|
||||
|
||||
public byte[] ReadBytes(int numberOfBytes)
|
||||
{
|
||||
return MsgReader.ReadBytes(buf, ref seekPos, numberOfBytes);
|
||||
}
|
||||
|
||||
public void PrepareForSending(ref byte[] outBuf, out bool isCompressed, out int outLength)
|
||||
{
|
||||
throw new InvalidOperationException("ReadWriteMessages are not to be sent");
|
||||
}
|
||||
}
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
using System;
|
||||
using System.Net;
|
||||
using Lidgren.Network;
|
||||
|
||||
namespace Barotrauma.Networking
|
||||
{
|
||||
public class LidgrenConnection : NetworkConnection
|
||||
{
|
||||
public NetConnection NetConnection { get; private set; }
|
||||
|
||||
public IPEndPoint IPEndPoint => NetConnection.RemoteEndPoint;
|
||||
|
||||
public string IPString
|
||||
{
|
||||
get
|
||||
{
|
||||
return IPEndPoint.Address.IsIPv4MappedToIPv6 ? IPEndPoint.Address.MapToIPv4().ToString() : IPEndPoint.Address.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
public UInt16 Port
|
||||
{
|
||||
get
|
||||
{
|
||||
return (UInt16)IPEndPoint.Port;
|
||||
}
|
||||
}
|
||||
|
||||
public LidgrenConnection(string name, NetConnection netConnection, UInt64 steamId)
|
||||
{
|
||||
Name = name;
|
||||
NetConnection = netConnection;
|
||||
SteamID = steamId;
|
||||
EndPointString = IPString;
|
||||
}
|
||||
}
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Net;
|
||||
|
||||
namespace Barotrauma.Networking
|
||||
{
|
||||
public enum NetworkConnectionStatus
|
||||
{
|
||||
Connected = 0x1,
|
||||
Disconnected = 0x2
|
||||
}
|
||||
|
||||
public abstract class NetworkConnection
|
||||
{
|
||||
public string Name;
|
||||
|
||||
public UInt64 SteamID
|
||||
{
|
||||
get;
|
||||
protected set;
|
||||
}
|
||||
|
||||
public string EndPointString
|
||||
{
|
||||
get;
|
||||
protected set;
|
||||
}
|
||||
|
||||
public NetworkConnectionStatus Status = NetworkConnectionStatus.Disconnected;
|
||||
}
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Barotrauma.Networking
|
||||
{
|
||||
public class SteamP2PConnection : NetworkConnection
|
||||
{
|
||||
public double Timeout = 0.0;
|
||||
|
||||
public SteamP2PConnection(string name, UInt64 steamId)
|
||||
{
|
||||
SteamID = steamId;
|
||||
EndPointString = SteamID.ToString();
|
||||
Name = name;
|
||||
Heartbeat();
|
||||
}
|
||||
|
||||
public void Decay(float deltaTime)
|
||||
{
|
||||
Timeout -= deltaTime;
|
||||
}
|
||||
|
||||
public void Heartbeat()
|
||||
{
|
||||
Timeout = 20.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -282,7 +282,7 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
RespawnCharactersProjSpecific();
|
||||
}
|
||||
|
||||
|
||||
public Vector2 FindSpawnPos()
|
||||
{
|
||||
if (Level.Loaded == null || Submarine.MainSub == null) { return Vector2.Zero; }
|
||||
@@ -310,12 +310,11 @@ namespace Barotrauma.Networking
|
||||
//make sure there aren't any walls too close
|
||||
var tooCloseCells = Level.Loaded.GetTooCloseCells(potentialSpawnPos.Position.ToVector2(), Math.Max(minWidth, minHeight));
|
||||
if (tooCloseCells.Any()) { continue; }
|
||||
|
||||
|
||||
//make sure the spawnpoint is far enough from other subs
|
||||
foreach (Submarine sub in Submarine.Loaded)
|
||||
{
|
||||
if (sub == RespawnShuttle || RespawnShuttle.DockedTo.Contains(sub)) { continue; }
|
||||
|
||||
float minDist = Math.Max(Math.Max(minWidth, minHeight) + Math.Max(sub.Borders.Width, sub.Borders.Height), 10000.0f);
|
||||
if (Vector2.DistanceSquared(sub.WorldPosition, potentialSpawnPos.Position.ToVector2()) < minDist * minDist)
|
||||
{
|
||||
|
||||
@@ -6,7 +6,7 @@ using System.Linq;
|
||||
|
||||
namespace Barotrauma.Networking
|
||||
{
|
||||
partial class ServerLog
|
||||
public partial class ServerLog
|
||||
{
|
||||
private struct LogMessage
|
||||
{
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Lidgren.Network;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
@@ -14,21 +13,21 @@ using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Networking
|
||||
{
|
||||
enum SelectionMode
|
||||
public enum SelectionMode
|
||||
{
|
||||
Manual = 0, Random = 1, Vote = 2
|
||||
}
|
||||
|
||||
enum YesNoMaybe
|
||||
public enum YesNoMaybe
|
||||
{
|
||||
No = 0, Maybe = 1, Yes = 2
|
||||
}
|
||||
|
||||
enum BotSpawnMode
|
||||
public enum BotSpawnMode
|
||||
{
|
||||
Normal, Fill
|
||||
}
|
||||
|
||||
|
||||
partial class ServerSettings : ISerializableEntity
|
||||
{
|
||||
public const string SettingsFile = "serversettings.xml";
|
||||
@@ -57,25 +56,17 @@ namespace Barotrauma.Networking
|
||||
|
||||
public class SavedClientPermission
|
||||
{
|
||||
public readonly string IP;
|
||||
public readonly string EndPoint;
|
||||
public readonly ulong SteamID;
|
||||
public readonly string Name;
|
||||
public List<DebugConsole.Command> PermittedCommands;
|
||||
|
||||
public ClientPermissions Permissions;
|
||||
|
||||
public SavedClientPermission(string name, IPAddress ip, ClientPermissions permissions, List<DebugConsole.Command> permittedCommands)
|
||||
public SavedClientPermission(string name, string endpoint, ClientPermissions permissions, List<DebugConsole.Command> permittedCommands)
|
||||
{
|
||||
this.Name = name;
|
||||
this.IP = ip.IsIPv4MappedToIPv6 ? ip.MapToIPv4().ToString() : ip.ToString();
|
||||
this.Permissions = permissions;
|
||||
this.PermittedCommands = permittedCommands;
|
||||
}
|
||||
public SavedClientPermission(string name, string ip, ClientPermissions permissions, List<DebugConsole.Command> permittedCommands)
|
||||
{
|
||||
this.Name = name;
|
||||
this.IP = ip;
|
||||
|
||||
this.EndPoint = endpoint;
|
||||
this.Permissions = permissions;
|
||||
this.PermittedCommands = permittedCommands;
|
||||
}
|
||||
@@ -139,9 +130,9 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
|
||||
public void Read(NetBuffer msg)
|
||||
public void Read(IReadMessage msg)
|
||||
{
|
||||
long oldPos = msg.Position;
|
||||
int oldPos = msg.BitPosition;
|
||||
UInt32 size = msg.ReadVariableUInt32();
|
||||
|
||||
float x; float y; float z; float w;
|
||||
@@ -152,7 +143,7 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
case "float":
|
||||
if (size != 4) break;
|
||||
property.SetValue(parentObject, msg.ReadFloat());
|
||||
property.SetValue(parentObject, msg.ReadSingle());
|
||||
return;
|
||||
case "int":
|
||||
if (size != 4) break;
|
||||
@@ -160,23 +151,23 @@ namespace Barotrauma.Networking
|
||||
return;
|
||||
case "vector2":
|
||||
if (size != 8) break;
|
||||
x = msg.ReadFloat();
|
||||
y = msg.ReadFloat();
|
||||
x = msg.ReadSingle();
|
||||
y = msg.ReadSingle();
|
||||
property.SetValue(parentObject, new Vector2(x, y));
|
||||
return;
|
||||
case "vector3":
|
||||
if (size != 12) break;
|
||||
x = msg.ReadFloat();
|
||||
y = msg.ReadFloat();
|
||||
z = msg.ReadFloat();
|
||||
x = msg.ReadSingle();
|
||||
y = msg.ReadSingle();
|
||||
z = msg.ReadSingle();
|
||||
property.SetValue(parentObject, new Vector3(x, y, z));
|
||||
return;
|
||||
case "vector4":
|
||||
if (size != 16) break;
|
||||
x = msg.ReadFloat();
|
||||
y = msg.ReadFloat();
|
||||
z = msg.ReadFloat();
|
||||
w = msg.ReadFloat();
|
||||
x = msg.ReadSingle();
|
||||
y = msg.ReadSingle();
|
||||
z = msg.ReadSingle();
|
||||
w = msg.ReadSingle();
|
||||
property.SetValue(parentObject, new Vector4(x, y, z, w));
|
||||
return;
|
||||
case "color":
|
||||
@@ -196,17 +187,17 @@ namespace Barotrauma.Networking
|
||||
property.SetValue(parentObject, new Rectangle(ix, iy, width, height));
|
||||
return;
|
||||
default:
|
||||
msg.Position = oldPos; //reset position to properly read the string
|
||||
msg.BitPosition = oldPos; //reset position to properly read the string
|
||||
string incVal = msg.ReadString();
|
||||
property.TrySetValue(parentObject, incVal);
|
||||
return;
|
||||
}
|
||||
|
||||
//size didn't match: skip this
|
||||
msg.Position += 8 * size;
|
||||
msg.BitPosition += (int)(8 * size);
|
||||
}
|
||||
|
||||
public void Write(NetBuffer msg, object overrideValue = null)
|
||||
public void Write(IWriteMessage msg, object overrideValue = null)
|
||||
{
|
||||
if (overrideValue == null) overrideValue = property.GetValue(parentObject);
|
||||
switch (typeString)
|
||||
@@ -287,7 +278,7 @@ namespace Barotrauma.Networking
|
||||
ServerName = serverName;
|
||||
Port = port;
|
||||
QueryPort = queryPort;
|
||||
//EnableUPnP = enableUPnP;
|
||||
EnableUPnP = enableUPnP;
|
||||
this.maxPlayers = maxPlayers;
|
||||
this.isPublic = isPublic;
|
||||
|
||||
@@ -328,7 +319,7 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public string ServerName;
|
||||
|
||||
private string serverMessageText;
|
||||
@@ -346,7 +337,9 @@ namespace Barotrauma.Networking
|
||||
public int Port;
|
||||
|
||||
public int QueryPort;
|
||||
|
||||
|
||||
public bool EnableUPnP;
|
||||
|
||||
public ServerLog ServerLog;
|
||||
|
||||
public Voting Voting;
|
||||
@@ -354,10 +347,10 @@ namespace Barotrauma.Networking
|
||||
public Dictionary<string, bool> MonsterEnabled { get; private set; }
|
||||
|
||||
public Dictionary<ItemPrefab, int> ExtraCargo { get; private set; }
|
||||
|
||||
|
||||
private TimeSpan sparseUpdateInterval = new TimeSpan(0, 0, 0, 3);
|
||||
private float selectedLevelDifficulty;
|
||||
private string password;
|
||||
private byte[] password;
|
||||
|
||||
public float AutoRestartTimer;
|
||||
|
||||
@@ -370,7 +363,7 @@ namespace Barotrauma.Networking
|
||||
public List<SavedClientPermission> ClientPermissions { get; private set; } = new List<SavedClientPermission>();
|
||||
|
||||
public WhiteList Whitelist { get; private set; }
|
||||
|
||||
|
||||
[Serialize(20, true)]
|
||||
public int TickRate
|
||||
{
|
||||
@@ -446,7 +439,7 @@ namespace Barotrauma.Networking
|
||||
ServerDetailsChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[Serialize(true, true)]
|
||||
public bool EndRoundAtLevelEnd
|
||||
{
|
||||
@@ -514,9 +507,15 @@ namespace Barotrauma.Networking
|
||||
|
||||
public bool HasPassword
|
||||
{
|
||||
get { return !string.IsNullOrEmpty(password); }
|
||||
get { return password != null; }
|
||||
#if CLIENT
|
||||
set
|
||||
{
|
||||
password = value ? (password ?? new byte[1]) : null;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
[Serialize(true, true)]
|
||||
public bool AllowVoteKick
|
||||
{
|
||||
@@ -555,7 +554,7 @@ namespace Barotrauma.Networking
|
||||
ServerDetailsChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[Serialize(0, true)]
|
||||
public int BotCount
|
||||
{
|
||||
@@ -569,7 +568,8 @@ namespace Barotrauma.Networking
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
|
||||
[Serialize(BotSpawnMode.Normal, true)]
|
||||
public BotSpawnMode BotSpawnMode
|
||||
{
|
||||
get;
|
||||
@@ -588,7 +588,7 @@ namespace Barotrauma.Networking
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
|
||||
[Serialize(true, true)]
|
||||
public bool AllowRewiring
|
||||
{
|
||||
@@ -604,6 +604,7 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
|
||||
private YesNoMaybe traitorsEnabled;
|
||||
[Serialize(YesNoMaybe.No, true)]
|
||||
public YesNoMaybe TraitorsEnabled
|
||||
{
|
||||
get { return traitorsEnabled; }
|
||||
@@ -615,6 +616,13 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
|
||||
[Serialize(defaultValue: 1, isSaveable: true)]
|
||||
public int TraitorsMinPlayerCount
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
private SelectionMode subSelectionMode;
|
||||
[Serialize(SelectionMode.Manual, true)]
|
||||
public SelectionMode SubSelectionMode
|
||||
@@ -642,7 +650,7 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
|
||||
public BanList BanList { get; private set; }
|
||||
|
||||
|
||||
[Serialize(0.6f, true)]
|
||||
public float EndVoteRequiredRatio
|
||||
{
|
||||
@@ -663,7 +671,7 @@ namespace Barotrauma.Networking
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
|
||||
[Serialize(120.0f, true)]
|
||||
public float KickAFKTime
|
||||
{
|
||||
@@ -671,20 +679,6 @@ namespace Barotrauma.Networking
|
||||
private set;
|
||||
}
|
||||
|
||||
[Serialize(true, true)]
|
||||
public bool TraitorUseRatio
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
[Serialize(0.2f, true)]
|
||||
public float TraitorRatio
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
private bool karmaEnabled;
|
||||
[Serialize(false, true)]
|
||||
public bool KarmaEnabled
|
||||
@@ -719,7 +713,7 @@ namespace Barotrauma.Networking
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
|
||||
public int MaxPlayers
|
||||
{
|
||||
get { return maxPlayers; }
|
||||
@@ -745,26 +739,42 @@ namespace Barotrauma.Networking
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
|
||||
public void SetPassword(string password)
|
||||
{
|
||||
if (string.IsNullOrEmpty(password))
|
||||
{
|
||||
this.password = "";
|
||||
this.password = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.password = Encoding.UTF8.GetString(NetUtility.ComputeSHAHash(Encoding.UTF8.GetBytes(password)));
|
||||
this.password = Lidgren.Network.NetUtility.ComputeSHAHash(Encoding.UTF8.GetBytes(password));
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsPasswordCorrect(string input, int nonce)
|
||||
public static byte[] SaltPassword(byte[] password, int salt)
|
||||
{
|
||||
byte[] saltedPw = new byte[password.Length*2];
|
||||
for (int i = 0; i < password.Length; i++)
|
||||
{
|
||||
saltedPw[(i * 2)] = password[i];
|
||||
saltedPw[(i * 2) + 1] = (byte)((salt >> (8 * (i % 4))) & 0xff);
|
||||
}
|
||||
saltedPw = Lidgren.Network.NetUtility.ComputeSHAHash(saltedPw);
|
||||
return saltedPw;
|
||||
}
|
||||
|
||||
public bool IsPasswordCorrect(byte[] input, int salt)
|
||||
{
|
||||
if (!HasPassword) return true;
|
||||
string saltedPw = password;
|
||||
saltedPw = saltedPw + Convert.ToString(nonce);
|
||||
saltedPw = Encoding.UTF8.GetString(NetUtility.ComputeSHAHash(Encoding.UTF8.GetBytes(saltedPw)));
|
||||
return input == saltedPw;
|
||||
byte[] saltedPw = SaltPassword(password, salt);
|
||||
DebugConsole.NewMessage(ToolBox.ByteArrayToString(input)+" "+ToolBox.ByteArrayToString(saltedPw));
|
||||
if (input.Length != saltedPw.Length) return false;
|
||||
for (int i=0;i<input.Length;i++)
|
||||
{
|
||||
if (input[i] != saltedPw[i]) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -795,7 +805,7 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
|
||||
public void ReadMonsterEnabled(NetBuffer inc)
|
||||
public void ReadMonsterEnabled(IReadMessage inc)
|
||||
{
|
||||
InitMonstersEnabled();
|
||||
List<string> monsterNames = MonsterEnabled.Keys.ToList();
|
||||
@@ -806,7 +816,7 @@ namespace Barotrauma.Networking
|
||||
inc.ReadPadBits();
|
||||
}
|
||||
|
||||
public void WriteMonsterEnabled(NetBuffer msg, Dictionary<string, bool> monsterEnabled = null)
|
||||
public void WriteMonsterEnabled(IWriteMessage msg, Dictionary<string, bool> monsterEnabled = null)
|
||||
{
|
||||
//monster spawn settings
|
||||
if (monsterEnabled == null) monsterEnabled = MonsterEnabled;
|
||||
@@ -819,7 +829,7 @@ namespace Barotrauma.Networking
|
||||
msg.WritePadBits();
|
||||
}
|
||||
|
||||
public bool ReadExtraCargo(NetBuffer msg)
|
||||
public bool ReadExtraCargo(IReadMessage msg)
|
||||
{
|
||||
bool changed = false;
|
||||
UInt32 count = msg.ReadUInt32();
|
||||
@@ -844,7 +854,7 @@ namespace Barotrauma.Networking
|
||||
return changed;
|
||||
}
|
||||
|
||||
public void WriteExtraCargo(NetBuffer msg)
|
||||
public void WriteExtraCargo(IWriteMessage msg)
|
||||
{
|
||||
if (ExtraCargo == null)
|
||||
{
|
||||
|
||||
@@ -9,10 +9,20 @@ namespace Barotrauma.Steam
|
||||
{
|
||||
public const bool USE_STEAM = true;
|
||||
|
||||
public const int STEAMP2P_OWNER_PORT = 30000;
|
||||
|
||||
public const uint AppID = 602960;
|
||||
|
||||
|
||||
private Facepunch.Steamworks.Client client;
|
||||
private Server server;
|
||||
private Facepunch.Steamworks.Server server;
|
||||
|
||||
private static List<string> initializationErrors = new List<string>();
|
||||
public static IEnumerable<string> InitializationErrors
|
||||
{
|
||||
get { return initializationErrors; }
|
||||
}
|
||||
|
||||
public const string MetadataFileName = "filelist.xml";
|
||||
|
||||
private Dictionary<string, int> tagCommonness = new Dictionary<string, int>()
|
||||
{
|
||||
@@ -63,6 +73,34 @@ namespace Barotrauma.Steam
|
||||
instance = new SteamManager();
|
||||
}
|
||||
|
||||
public static ulong GetSteamID()
|
||||
{
|
||||
if (instance == null || !instance.isInitialized)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (instance.client != null)
|
||||
{
|
||||
return instance.client.SteamId;
|
||||
}
|
||||
else if (instance.server != null)
|
||||
{
|
||||
return instance.server.SteamId;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static string GetUsername()
|
||||
{
|
||||
if (instance == null || !instance.isInitialized || instance.client == null)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
return instance.client.Username;
|
||||
}
|
||||
|
||||
public static void OverlayCustomURL(string url)
|
||||
{
|
||||
if (instance == null || !instance.isInitialized || instance.client == null)
|
||||
@@ -146,5 +184,33 @@ namespace Barotrauma.Steam
|
||||
instance.server = null;
|
||||
instance = null;
|
||||
}
|
||||
|
||||
public static UInt64 SteamIDStringToUInt64(string str)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(str)) { return 0; }
|
||||
UInt64 retVal;
|
||||
if (UInt64.TryParse(str, out retVal) && retVal >(1<<52)) { return retVal; }
|
||||
if (str.ToUpper().IndexOf("STEAM_") != 0) { return 0; }
|
||||
string[] split = str.Substring(6).Split(':');
|
||||
if (split.Length != 3) { return 0; }
|
||||
|
||||
UInt64 universe = 0; UInt64 y = 0; UInt64 accountNumber = 0;
|
||||
if (!UInt64.TryParse(split[0], out universe)) { return 0; }
|
||||
if (!UInt64.TryParse(split[1], out y)) { return 0; }
|
||||
if (!UInt64.TryParse(split[2], out accountNumber)) { return 0; }
|
||||
|
||||
UInt64 accountInstance = 1; UInt64 accountType = 1;
|
||||
|
||||
return (universe << 56) | (accountType << 52) | (accountInstance << 32) | (accountNumber << 1) | y;
|
||||
}
|
||||
|
||||
public static string SteamIDUInt64ToString(UInt64 uint64)
|
||||
{
|
||||
UInt64 y = uint64 & 0x1;
|
||||
UInt64 accountNumber = (uint64 >> 1) & 0x7fffffff;
|
||||
UInt64 universe = (uint64 >> 56) & 0xff;
|
||||
|
||||
return "STEAM_" + universe.ToString() + ":" + y.ToString() + ":" + accountNumber.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Lidgren.Network;
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Lidgren.Network;
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Microsoft.Xna.Framework;
|
||||
@@ -113,7 +112,7 @@ namespace Barotrauma.Networking
|
||||
outBuf = null;
|
||||
}
|
||||
|
||||
public virtual void Write(NetBuffer msg)
|
||||
public virtual void Write(IWriteMessage msg)
|
||||
{
|
||||
if (!CanSend) throw new Exception("Called Write on a VoipQueue not set up for sending");
|
||||
|
||||
@@ -127,7 +126,7 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
|
||||
public virtual bool Read(NetBuffer msg)
|
||||
public virtual bool Read(IReadMessage msg)
|
||||
{
|
||||
if (!CanReceive) throw new Exception("Called Read on a VoipQueue not set up for receiving");
|
||||
|
||||
@@ -138,7 +137,7 @@ namespace Barotrauma.Networking
|
||||
for (int i = 0; i < BUFFER_COUNT; i++)
|
||||
{
|
||||
bufferLengths[i] = msg.ReadByte();
|
||||
msg.ReadBytes(buffers[i], 0, bufferLengths[i]);
|
||||
buffers[i] = msg.ReadBytes(bufferLengths[i]);
|
||||
}
|
||||
newestBufferInd = BUFFER_COUNT - 1;
|
||||
LatestBufferID = incLatestBufferID;
|
||||
@@ -150,7 +149,7 @@ namespace Barotrauma.Networking
|
||||
for (int i = 0; i < BUFFER_COUNT; i++)
|
||||
{
|
||||
byte len = msg.ReadByte();
|
||||
msg.Position += len * 8;
|
||||
msg.BitPosition += len * 8;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
using FarseerPhysics;
|
||||
using FarseerPhysics.Dynamics;
|
||||
using FarseerPhysics.Factories;
|
||||
using Lidgren.Network;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
@@ -12,7 +12,7 @@ using System.Xml.Linq;
|
||||
namespace Barotrauma
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Property)]
|
||||
public class Editable : Attribute
|
||||
class Editable : Attribute
|
||||
{
|
||||
public int MaxLength;
|
||||
public int DecimalCount = 1;
|
||||
@@ -45,7 +45,7 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Property)]
|
||||
public class InGameEditable : Editable
|
||||
class InGameEditable : Editable
|
||||
{
|
||||
}
|
||||
|
||||
@@ -166,7 +166,6 @@ namespace Barotrauma
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
switch (typeName)
|
||||
{
|
||||
case "bool":
|
||||
@@ -175,20 +174,26 @@ namespace Barotrauma
|
||||
propertyInfo.SetValue(parentObject, boolValue, null);
|
||||
break;
|
||||
case "int":
|
||||
int intVal;
|
||||
if (int.TryParse(value, out intVal))
|
||||
if (int.TryParse(value, out int intVal))
|
||||
{
|
||||
if (TrySetValueWithoutReflection(parentObject, intVal)) { return true; }
|
||||
propertyInfo.SetValue(parentObject, intVal, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case "float":
|
||||
float floatVal;
|
||||
if (float.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out floatVal))
|
||||
if (float.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out float floatVal))
|
||||
{
|
||||
if (TrySetValueWithoutReflection(parentObject, floatVal)) { return true; }
|
||||
propertyInfo.SetValue(parentObject, floatVal, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case "string":
|
||||
propertyInfo.SetValue(parentObject, value, null);
|
||||
@@ -420,6 +425,9 @@ namespace Barotrauma
|
||||
case "Charge":
|
||||
if (parentObject is PowerContainer powerContainer) { return powerContainer.Charge; }
|
||||
break;
|
||||
case "Overload":
|
||||
if (parentObject is PowerTransfer powerTransfer) { return powerTransfer.Overload; }
|
||||
break;
|
||||
case "AvailableFuel":
|
||||
{ if (parentObject is Reactor reactor) { return reactor.AvailableFuel; } }
|
||||
break;
|
||||
@@ -662,5 +670,33 @@ namespace Barotrauma
|
||||
element.SetAttributeValue(property.NameToLowerInvariant, stringValue);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Upgrade the properties of an entity saved with an older version of the game. Properties that should be upgraded are defined using "Upgrade" elements in the config file.
|
||||
/// for example, <Upgrade gameversion="0.9.2.0" scale="0.5"/> would force the scale of the entity to 0.5 if it was saved with a version prior to 0.9.2.0.
|
||||
/// </summary>
|
||||
/// <param name="entity">The entity to upgrade</param>
|
||||
/// <param name="configElement">The XML element to get the upgrade instructions from (e.g. the config of an item prefab)</param>
|
||||
/// <param name="savedVersion">The game version the entity was saved with</param>
|
||||
public static void UpgradeGameVersion(ISerializableEntity entity, XElement configElement, Version savedVersion)
|
||||
{
|
||||
foreach (XElement subElement in configElement.Elements())
|
||||
{
|
||||
if (subElement.Name.ToString().ToLowerInvariant() != "upgrade") { continue; }
|
||||
var upgradeVersion = new Version(subElement.GetAttributeString("gameversion", "0.0.0.0"));
|
||||
if (savedVersion < upgradeVersion)
|
||||
{
|
||||
foreach (XAttribute attribute in subElement.Attributes())
|
||||
{
|
||||
string attributeName = attribute.Name.ToString().ToLowerInvariant();
|
||||
if (attributeName == "gameversion") { continue; }
|
||||
if (entity.SerializableProperties.TryGetValue(attributeName, out SerializableProperty property))
|
||||
{
|
||||
property.TrySetValue(entity, attribute.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -289,6 +289,30 @@ namespace Barotrauma
|
||||
|
||||
return intValue;
|
||||
}
|
||||
public static ushort[] GetAttributeUshortArray(this XElement element, string name, ushort[] defaultValue)
|
||||
{
|
||||
if (element?.Attribute(name) == null) return defaultValue;
|
||||
|
||||
string stringValue = element.Attribute(name).Value;
|
||||
if (string.IsNullOrEmpty(stringValue)) return defaultValue;
|
||||
|
||||
string[] splitValue = stringValue.Split(',');
|
||||
ushort[] ushortValue = new ushort[splitValue.Length];
|
||||
for (int i = 0; i < splitValue.Length; i++)
|
||||
{
|
||||
try
|
||||
{
|
||||
ushort val = ushort.Parse(splitValue[i]);
|
||||
ushortValue[i] = val;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
DebugConsole.ThrowError("Error in " + element + "! ", e);
|
||||
}
|
||||
}
|
||||
|
||||
return ushortValue;
|
||||
}
|
||||
|
||||
public static bool GetAttributeBool(this XElement element, string name, bool defaultValue)
|
||||
{
|
||||
|
||||
@@ -259,23 +259,22 @@ namespace Barotrauma
|
||||
#if SERVER
|
||||
if (GameMain.Server?.TraitorManager != null)
|
||||
{
|
||||
foreach (Traitor traitor in GameMain.Server.TraitorManager.TraitorList)
|
||||
if (GameMain.Server.TraitorManager.IsTraitor(character))
|
||||
{
|
||||
if (traitor.TargetCharacter == character)
|
||||
{
|
||||
//killed the target as a traitor
|
||||
UnlockAchievement(traitor.Character, "traitorwin");
|
||||
}
|
||||
else if (traitor.Character == character)
|
||||
{
|
||||
//someone killed a traitor
|
||||
UnlockAchievement(causeOfDeath.Killer, "killtraitor");
|
||||
}
|
||||
UnlockAchievement(causeOfDeath.Killer, "killtraitor");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
public static void OnTraitorWin(Character character)
|
||||
{
|
||||
#if CLIENT
|
||||
if (GameMain.Client != null || GameMain.GameSession == null) return;
|
||||
#endif
|
||||
UnlockAchievement(character, "traitorwin");
|
||||
}
|
||||
|
||||
public static void OnRoundEnded(GameSession gameSession)
|
||||
{
|
||||
//made it to the destination
|
||||
@@ -303,13 +302,11 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
#if CLIENT
|
||||
if (GameMain.Client != null) { return; }
|
||||
#endif
|
||||
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsClient) { return; }
|
||||
|
||||
if (gameSession.Mission != null)
|
||||
{
|
||||
if (gameSession.Mission is CombatMission combatMission)
|
||||
if (gameSession.Mission is CombatMission combatMission && GameMain.GameSession.WinningTeam.HasValue)
|
||||
{
|
||||
//all characters that are alive and in the winning team get an achievement
|
||||
UnlockAchievement(gameSession.Mission.Prefab.AchievementIdentifier + (int)GameMain.GameSession.WinningTeam, true,
|
||||
|
||||
@@ -69,7 +69,7 @@ namespace Barotrauma
|
||||
}
|
||||
return language;
|
||||
}
|
||||
|
||||
|
||||
public static void LoadTextPacks(IEnumerable<ContentPackage> selectedContentPackages)
|
||||
{
|
||||
availableLanguages.Clear();
|
||||
@@ -311,10 +311,83 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
return string.Format(text, args);
|
||||
return string.Format(text, args);
|
||||
}
|
||||
|
||||
public static string FormatServerMessage(string textId)
|
||||
{
|
||||
return $"{textId}~";
|
||||
}
|
||||
|
||||
public static string FormatServerMessage(string message, IEnumerable<string> keys, IEnumerable<string> values)
|
||||
{
|
||||
if (keys == null || values == null || !keys.Any() || !values.Any())
|
||||
{
|
||||
return FormatServerMessage(message);
|
||||
}
|
||||
var startIndex = message.LastIndexOf('/') + 1;
|
||||
var endIndex = message.IndexOf('~', startIndex);
|
||||
if (endIndex == -1)
|
||||
{
|
||||
endIndex = message.Length - 1;
|
||||
}
|
||||
var textId = message.Substring(startIndex, endIndex - startIndex + 1);
|
||||
var keysWithValues = keys.Zip(values, (key, value) => new { Key = key, Value = value });
|
||||
var prefixEntries = keysWithValues.Select((kv, index) =>
|
||||
{
|
||||
if (kv.Value.IndexOfAny(new char[] { '~', '/' }) != -1)
|
||||
{
|
||||
var kvStartIndex = kv.Value.LastIndexOf('/') + 1;
|
||||
return kv.Value.Substring(0, kvStartIndex) + $"[{textId}.{index}]={kv.Value.Substring(kvStartIndex)}";
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}).Where(e => e != null).ToArray();
|
||||
return string.Join("",
|
||||
(prefixEntries.Length > 0 ? string.Join("/", prefixEntries) + "/" : ""),
|
||||
message,
|
||||
string.Join("", keysWithValues.Select((kv, index) => kv.Value.IndexOfAny(new char[] { '~', '/' }) != -1 ? $"~{kv.Key}=[{textId}.{index}]" : $"~{kv.Key}={kv.Value}").ToArray())
|
||||
);
|
||||
}
|
||||
|
||||
static readonly string[] genderPronounVariables = new string[] {
|
||||
"[genderpronoun]",
|
||||
"[genderpronounpossessive]",
|
||||
"[genderpronounreflexive]",
|
||||
"[Genderpronoun]",
|
||||
"[Genderpronounpossessive]",
|
||||
"[Genderpronounreflexive]"
|
||||
};
|
||||
|
||||
static readonly string[] genderPronounMaleValues = new string[] {
|
||||
"PronounMaleLowercase",
|
||||
"PronounPossessiveMaleLowercase",
|
||||
"PronounReflexiveMaleLowercase",
|
||||
"PronounMale",
|
||||
"PronounPossessiveMale",
|
||||
"PronounReflexiveMale"
|
||||
};
|
||||
|
||||
static readonly string[] genderPronounFemaleValues = new string[] {
|
||||
"PronounFemaleLowercase",
|
||||
"PronounPossessiveFemaleLowercase",
|
||||
"PronounReflexiveFemaleLowercase",
|
||||
"PronounMale",
|
||||
"PronounPossessiveFemale",
|
||||
"PronounReflexiveFemale"
|
||||
};
|
||||
|
||||
public static string FormatServerMessageWithGenderPronouns(Gender gender, string message, IEnumerable<string> keys, IEnumerable<string> values)
|
||||
{
|
||||
return FormatServerMessage(message, keys.Concat(genderPronounVariables), values.Concat(gender == Gender.Male ? genderPronounMaleValues : genderPronounFemaleValues));
|
||||
}
|
||||
|
||||
static readonly Regex reReplacedMessage = new Regex(@"^(?<variable>[\[\].A-Za-z0-9_]+?)=(?<message>.*)$", RegexOptions.Compiled);
|
||||
|
||||
// Format: ServerMessage.Identifier1/ServerMessage.Indentifier2~[variable1]=value~[variable2]=value
|
||||
// Also: replacement=ServerMessage.Identifier1~[variable1]=value/ServerMessage.Identifier2~[variable2]=replacement
|
||||
public static string GetServerMessage(string serverMessage)
|
||||
{
|
||||
if (!textPacks.ContainsKey(Language))
|
||||
@@ -328,6 +401,7 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
string[] messages = serverMessage.Split('/');
|
||||
var replacedMessages = new Dictionary<string, string>();
|
||||
|
||||
bool translationsFound = false;
|
||||
|
||||
@@ -335,8 +409,17 @@ namespace Barotrauma
|
||||
{
|
||||
for (int i = 0; i < messages.Length; i++)
|
||||
{
|
||||
if (!IsServerMessageWithVariables(messages[i])) // No variables, try to translate
|
||||
if (messages[i].EndsWith("~", StringComparison.Ordinal))
|
||||
{
|
||||
messages[i] = messages[i].Substring(0, messages[i].Length - 1);
|
||||
}
|
||||
if (!IsServerMessageWithVariables(messages[i]) && !messages[i].Contains('=')) // No variables, try to translate
|
||||
{
|
||||
foreach (var replacedMessage in replacedMessages)
|
||||
{
|
||||
messages[i] = messages[i].Replace(replacedMessage.Key, replacedMessage.Value);
|
||||
}
|
||||
|
||||
if (messages[i].Contains(" ")) continue; // Spaces found, do not translate
|
||||
string msg = Get(messages[i], true);
|
||||
if (msg != null) // If a translation was found, otherwise use the original
|
||||
@@ -347,7 +430,22 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
var match = reReplacedMessage.Match(messages[i]);
|
||||
string messageVariable = null;
|
||||
if (match.Success)
|
||||
{
|
||||
messageVariable = match.Groups["variable"].ToString();
|
||||
messages[i] = match.Groups["message"].ToString();
|
||||
}
|
||||
|
||||
foreach (var replacedMessage in replacedMessages)
|
||||
{
|
||||
messages[i] = messages[i].Replace(replacedMessage.Key, replacedMessage.Value);
|
||||
}
|
||||
|
||||
|
||||
string[] messageWithVariables = messages[i].Split('~');
|
||||
|
||||
string msg = Get(messageWithVariables[0], true);
|
||||
|
||||
if (msg != null) // If a translation was found, otherwise use the original
|
||||
@@ -355,7 +453,7 @@ namespace Barotrauma
|
||||
messages[i] = msg;
|
||||
translationsFound = true;
|
||||
}
|
||||
else
|
||||
else if (messageVariable == null)
|
||||
{
|
||||
continue; // No translation found, probably caused by player input -> skip variable handling
|
||||
}
|
||||
@@ -366,6 +464,12 @@ namespace Barotrauma
|
||||
string[] variableAndValue = messageWithVariables[j].Split('=');
|
||||
messages[i] = messages[i].Replace(variableAndValue[0], variableAndValue[1]);
|
||||
}
|
||||
|
||||
if (messageVariable != null)
|
||||
{
|
||||
replacedMessages[messageVariable] = messages[i];
|
||||
messages[i] = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -374,7 +478,10 @@ namespace Barotrauma
|
||||
string translatedServerMessage = string.Empty;
|
||||
for (int i = 0; i < messages.Length; i++)
|
||||
{
|
||||
translatedServerMessage += messages[i];
|
||||
if (messages[i] != null)
|
||||
{
|
||||
translatedServerMessage += messages[i];
|
||||
}
|
||||
}
|
||||
return translatedServerMessage;
|
||||
}
|
||||
@@ -427,7 +534,7 @@ namespace Barotrauma
|
||||
}
|
||||
return string.Join(separator, texts);
|
||||
}
|
||||
|
||||
|
||||
public static string EnsureUTF8(string text)
|
||||
{
|
||||
byte[] bytes = Encoding.Default.GetBytes(text);
|
||||
@@ -494,24 +601,24 @@ namespace Barotrauma
|
||||
{
|
||||
if (gender == Gender.Male)
|
||||
{
|
||||
return text.Replace("[genderpronoun]", Get("PronounMale").ToLower())
|
||||
.Replace("[genderpronounpossessive]", Get("PronounPossessiveMale").ToLower())
|
||||
.Replace("[genderpronounreflexive]", Get("PronounReflexiveMale").ToLower())
|
||||
.Replace("[Genderpronoun]", Capitalize(Get("PronounMale")))
|
||||
.Replace("[Genderpronounpossessive]", Capitalize(Get("PronounPossessiveMale")))
|
||||
.Replace("[Genderpronounreflexive]", Capitalize(Get("PronounReflexiveMale")));
|
||||
return text.Replace("[genderpronoun]", Get("PronounMaleLowercase"))
|
||||
.Replace("[genderpronounpossessive]", Get("PronounPossessiveMaleLowercase"))
|
||||
.Replace("[genderpronounreflexive]", Get("PronounReflexiveMaleLowercase"))
|
||||
.Replace("[Genderpronoun]", Get("PronounMale"))
|
||||
.Replace("[Genderpronounpossessive]", Get("PronounPossessiveMale"))
|
||||
.Replace("[Genderpronounreflexive]", Get("PronounReflexiveMale"));
|
||||
}
|
||||
else
|
||||
{
|
||||
return text.Replace("[genderpronoun]", Get("PronounFemale").ToLower())
|
||||
.Replace("[genderpronounpossessive]", Get("PronounPossessiveFemale").ToLower())
|
||||
.Replace("[genderpronounreflexive]", Get("PronounReflexiveFemale").ToLower())
|
||||
.Replace("[Genderpronoun]", Capitalize(Get("PronounFemale")))
|
||||
.Replace("[Genderpronounpossessive]", Capitalize(Get("PronounPossessiveFemale")))
|
||||
.Replace("[Genderpronounreflexive]", Capitalize(Get("PronounReflexiveFemale")));
|
||||
return text.Replace("[genderpronoun]", Get("PronounFemaleLowercase"))
|
||||
.Replace("[genderpronounpossessive]", Get("PronounPossessiveFemaleLowercase"))
|
||||
.Replace("[genderpronounreflexive]", Get("PronounReflexiveFemaleLowerCase"))
|
||||
.Replace("[Genderpronoun]", Get("PronounFemale"))
|
||||
.Replace("[Genderpronounpossessive]", Get("PronounPossessiveFemale"))
|
||||
.Replace("[Genderpronounreflexive]", Get("PronounReflexiveFemale"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static Regex isCJK = new Regex(
|
||||
@"\p{IsHangulJamo}|" +
|
||||
@"\p{IsCJKRadicalsSupplement}|" +
|
||||
|
||||
@@ -50,6 +50,10 @@ namespace Barotrauma
|
||||
|
||||
public string Get(string textTag)
|
||||
{
|
||||
if (string.IsNullOrEmpty(textTag))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if (!texts.TryGetValue(textTag.ToLowerInvariant(), out List<string> textList) || !textList.Any())
|
||||
{
|
||||
return null;
|
||||
|
||||
@@ -404,7 +404,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public static void CopyFolder(string sourceDirName, string destDirName, bool copySubDirs)
|
||||
public static void CopyFolder(string sourceDirName, string destDirName, bool copySubDirs, bool overwriteExisting = false)
|
||||
{
|
||||
// Get the subdirectories for the specified directory.
|
||||
DirectoryInfo dir = new DirectoryInfo(sourceDirName);
|
||||
@@ -428,6 +428,10 @@ namespace Barotrauma
|
||||
foreach (FileInfo file in files)
|
||||
{
|
||||
string temppath = Path.Combine(destDirName, file.Name);
|
||||
if (overwriteExisting && File.Exists(temppath))
|
||||
{
|
||||
File.Delete(temppath);
|
||||
}
|
||||
file.CopyTo(temppath, false);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Lidgren.Network;
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
@@ -7,6 +6,7 @@ using System.Security.Cryptography;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Barotrauma.Networking;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
@@ -313,13 +313,16 @@ namespace Barotrauma
|
||||
/// <summary>
|
||||
/// Reads a number of bits from the buffer and inserts them to a new NetBuffer instance
|
||||
/// </summary>
|
||||
public static NetBuffer ExtractBits(this NetBuffer originalBuffer, int numberOfBits)
|
||||
public static IReadMessage ExtractBits(this IReadMessage originalBuffer, int numberOfBits)
|
||||
{
|
||||
var buffer = new NetBuffer();
|
||||
byte[] data = new byte[(int)Math.Ceiling(numberOfBits / (double)8)];
|
||||
|
||||
originalBuffer.ReadBits(data, 0, numberOfBits);
|
||||
buffer.Write(data);
|
||||
var buffer = new ReadWriteMessage();
|
||||
|
||||
for (int i=0;i<numberOfBits;i++)
|
||||
{
|
||||
bool bit = originalBuffer.ReadBoolean();
|
||||
buffer.Write(bit);
|
||||
}
|
||||
buffer.BitPosition = 0;
|
||||
|
||||
return buffer;
|
||||
}
|
||||
@@ -407,5 +410,13 @@ namespace Barotrauma
|
||||
//}
|
||||
return destination;
|
||||
}
|
||||
|
||||
public static string ByteArrayToString(byte[] ba)
|
||||
{
|
||||
StringBuilder hex = new StringBuilder(ba.Length * 2);
|
||||
foreach (byte b in ba)
|
||||
hex.AppendFormat("{0:x2}", b);
|
||||
return hex.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user