Unstable 0.17.1.0

This commit is contained in:
Markus Isberg
2022-03-17 01:25:04 +09:00
parent 3974067915
commit 6d410cc1b7
302 changed files with 5878 additions and 3317 deletions
@@ -507,7 +507,7 @@ namespace Barotrauma.Items.Components
list.Remove(this);
}
public void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
public void ServerEventWrite(IWriteMessage msg, Client c, NetEntityEvent.IData extraData = null)
{
//no further data needed, the event just triggers the discharge
}
@@ -229,7 +229,6 @@ namespace Barotrauma.Items.Components
int amount = Rand.Range(minAmount, maxAmount, Rand.RandSync.Unsynced);
Vector2 offset = SpawnAreaOffset;
offset.Y = -offset.Y;
switch (SpawnAreaShape)
{
@@ -707,7 +707,7 @@ namespace Barotrauma.Items.Components
#if SERVER
for (int i = 0; i < Vines.Count; i += VineChunkSize)
{
GameMain.Server.CreateEntityEvent(item, new object[] { NetEntityEvent.Type.ComponentState, item.GetComponentIndex(this), i });
item.CreateServerEvent(this, new EventData(offset: i));
}
#elif CLIENT
ResetPlanterSize();
@@ -12,6 +12,16 @@ namespace Barotrauma.Items.Components
{
partial class Holdable : Pickable, IServerSerializable, IClientSerializable
{
private readonly struct EventData : IEventData
{
public readonly Vector2 AttachPos;
public EventData(Vector2 attachPos)
{
AttachPos = attachPos;
}
}
const float MaxAttachDistance = 150.0f;
//the position(s) in the item that the Character grabs
@@ -155,8 +165,8 @@ namespace Barotrauma.Items.Components
[Editable, Serialize(false, IsPropertySaveable.No, description: "Should the item swing around when it's being used (for example, when firing a weapon or a welding tool).")]
public bool SwingWhenUsing { get; set; }
[ConditionallyEditable(ConditionallyEditable.ConditionType.Attachable, MinValueFloat = 0.0f, MaxValueFloat = 0.999f, DecimalCount = 3), Serialize(0.85f, IsPropertySaveable.No, description: "Sprite depth that's used when the item is attached to a wall.")]
public float SpriteDepthWhenAttached
[ConditionallyEditable(ConditionallyEditable.ConditionType.Attachable, MinValueFloat = 0.0f, MaxValueFloat = 0.999f, DecimalCount = 3), Serialize(0.55f, IsPropertySaveable.No, description: "Sprite depth that's used when the item is NOT attached to a wall.")]
public float SpriteDepthWhenDropped
{
get;
set;
@@ -244,12 +254,12 @@ namespace Barotrauma.Items.Components
}
}
private bool loadedFromXml;
private bool loadedFromInstance;
public override void Load(ContentXElement componentElement, bool usePrefabValues, IdRemap idRemap)
{
base.Load(componentElement, usePrefabValues, idRemap);
loadedFromXml = true;
loadedFromInstance = true;
if (usePrefabValues)
{
@@ -583,7 +593,7 @@ namespace Barotrauma.Items.Components
Attached = true;
#if CLIENT
item.DrawDepthOffset = SpriteDepthWhenAttached - item.SpriteDepth;
item.DrawDepthOffset = 0.0f;
#endif
}
@@ -600,6 +610,9 @@ namespace Barotrauma.Items.Components
requiredItems.Clear();
DisplayMsg = "";
PickKey = InputType.Select;
#if CLIENT
item.DrawDepthOffset = SpriteDepthWhenDropped - item.SpriteDepth;
#endif
}
public override void ParseMsg()
@@ -663,12 +676,7 @@ namespace Barotrauma.Items.Components
{
#if CLIENT
Vector2 attachPos = ConvertUnits.ToSimUnits(GetAttachPosition(character));
GameMain.Client.CreateEntityEvent(item, new object[]
{
NetEntityEvent.Type.ComponentState,
item.GetComponentIndex(this),
attachPos
});
item.CreateClientEvent(this, new EventData(attachPos));
#endif
}
return false;
@@ -867,8 +875,8 @@ namespace Barotrauma.Items.Components
{
if (!attachable) { return; }
//a mod has overridden the item, and the base item didn't have a Holdable component = a mod made the item movable/detachable
if (item.Prefab.IsOverride && !loadedFromXml)
//the Holdable component didn't get loaded from an instance of the item, just the prefab xml = a mod or update must've made the item movable/detachable
if (!loadedFromInstance)
{
if (attachedByDefault)
{
@@ -67,7 +67,6 @@ namespace Barotrauma.Items.Components
[Serialize("#ffffff", IsPropertySaveable.Yes, alwaysUseInstanceValues: true)]
public Color OwnerSkinColor { get; set; }
#warning TODO: figure out how to set Vector2.Zero as the default here
[Serialize("0,0", IsPropertySaveable.Yes, alwaysUseInstanceValues: true)]
public Vector2 OwnerSheetIndex { get; set; }
@@ -436,13 +436,10 @@ namespace Barotrauma.Items.Components
#if SERVER
if (GameMain.Server != null && targetCharacter != null) //TODO: Log structure hits
{
GameMain.Server.CreateEntityEvent(item, new object[]
{
Networking.NetEntityEvent.Type.ApplyStatusEffect,
GameMain.Server.CreateEntityEvent(item, new Item.ApplyStatusEffectEventData(
success ? ActionType.OnUse : ActionType.OnFailure,
null, //itemcomponent
targetCharacter.ID, targetLimb
});
targetItemComponent: null,
targetCharacter, targetLimb));
string logStr = picker?.LogName + " used " + item.Name;
if (item.ContainedItems != null && item.ContainedItems.Any())
@@ -282,12 +282,12 @@ namespace Barotrauma.Items.Components
}
}
public virtual void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
public virtual void ServerEventWrite(IWriteMessage msg, Client c, NetEntityEvent.IData extraData = null)
{
msg.Write(activePicker == null ? (ushort)0 : activePicker.ID);
msg.Write(activePicker?.ID ?? (ushort)0);
}
public virtual void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
public virtual void ClientEventRead(IReadMessage msg, float sendingTime)
{
ushort pickerID = msg.ReadUInt16();
if (pickerID == 0)
@@ -178,11 +178,11 @@ namespace Barotrauma.Items.Components
throwDone = true;
IsActive = true;
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsServer)
if (GameMain.NetworkMember is { IsServer: true })
{
GameMain.NetworkMember.CreateEntityEvent(item, new object[] { NetEntityEvent.Type.ApplyStatusEffect, ActionType.OnSecondaryUse, this, CurrentThrower.ID });
GameMain.NetworkMember.CreateEntityEvent(item, new Item.ApplyStatusEffectEventData(ActionType.OnSecondaryUse, this, CurrentThrower));
}
if (GameMain.NetworkMember == null || GameMain.NetworkMember.IsServer)
if (!(GameMain.NetworkMember is { IsClient: true }))
{
//Stun grenades, flares, etc. all have their throw-related things handled in "onSecondaryUse"
ApplyStatusEffects(ActionType.OnSecondaryUse, deltaTime, CurrentThrower, user: CurrentThrower);
@@ -6,6 +6,7 @@ using System.Reflection;
using System.Xml.Linq;
using Barotrauma.Extensions;
using Barotrauma.IO;
using Barotrauma.Networking;
#if CLIENT
using Microsoft.Xna.Framework.Graphics;
using Barotrauma.Sounds;
@@ -1036,6 +1037,30 @@ namespace Barotrauma.Items.Components
}
}
public interface IEventData { }
public virtual bool ValidateEventData(NetEntityEvent.IData data)
=> true;
protected T ExtractEventData<T>(NetEntityEvent.IData data) where T : IEventData
=> TryExtractEventData(data, out T componentData)
? componentData
: throw new Exception($"Malformed item component state event for {item.Name} " +
$"(item ID {item.ID}, component type {GetType().Name}): " +
$"could not extract ComponentData of type {typeof(T).Name}");
protected bool TryExtractEventData<T>(NetEntityEvent.IData data, out T componentData)
{
componentData = default;
if (data is Item.ComponentStateEventData { ComponentData: T nestedData })
{
componentData = nestedData;
return true;
}
return false;
}
#region AI related
protected const float AIUpdateInterval = 0.2f;
protected float aiUpdateTimer;
@@ -370,7 +370,10 @@ namespace Barotrauma.Items.Components
public Item GetFocusTarget()
{
item.SendSignal(new Signal(MathHelper.ToDegrees(targetRotation).ToString("G", CultureInfo.InvariantCulture), sender: user), "position_out");
var positionOut = item.Connections.Find(c => c.Name == "position_out");
if (positionOut == null) { return null; }
item.SendSignal(new Signal(MathHelper.ToDegrees(targetRotation).ToString("G", CultureInfo.InvariantCulture), sender: user), positionOut);
for (int i = item.LastSentSignalRecipients.Count - 1; i >= 0; i--)
{
@@ -380,7 +383,16 @@ namespace Barotrauma.Items.Components
return item.LastSentSignalRecipients[i].Item;
}
}
foreach (var recipientPanel in item.GetConnectedComponentsRecursive<ConnectionPanel>(positionOut, allowTraversingBackwards: false))
{
if (recipientPanel.Item.Condition <= 0.0f) { continue; }
if (recipientPanel.Item.Prefab.FocusOnSelected)
{
return recipientPanel.Item;
}
}
return null;
}
@@ -221,7 +221,7 @@ namespace Barotrauma.Items.Components
}
float condition = deconstructProduct.CopyCondition ?
percentageHealth * itemPrefab.Health :
percentageHealth * itemPrefab.Health * deconstructProduct.OutConditionMax :
itemPrefab.Health * Rand.Range(deconstructProduct.OutConditionMin, deconstructProduct.OutConditionMax);
if (DeconstructItemsSimultaneously && deconstructProduct.RequiredOtherItem.Length > 0)
@@ -354,7 +354,14 @@ namespace Barotrauma.Items.Components
{
foreach (Item containedItem in availableItem.OwnInventory.AllItemsMod)
{
containedItem.Drop(dropper: null);
if (availableItem.GetComponent<ItemContainer>()?.RemoveContainedItemsOnDeconstruct ?? false)
{
Entity.Spawner.AddItemToRemoveQueue(containedItem);
}
else
{
containedItem.Drop(dropper: null);
}
}
}
@@ -169,7 +169,7 @@ namespace Barotrauma.Items.Components
hull.BallastFlora = new BallastFloraBehavior(hull, ballastFloraPrefab, offset, firstGrowth: true);
#if SERVER
hull.BallastFlora.SendNetworkMessage(hull.BallastFlora, BallastFloraBehavior.NetworkHeader.Spawn);
hull.BallastFlora.SendNetworkMessage(new BallastFloraBehavior.SpawnEventData());
#endif
}
@@ -1,11 +1,9 @@
using Barotrauma.Networking;
using Barotrauma.Extensions;
using Barotrauma.Networking;
using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using Barotrauma.Extensions;
using System.Globalization;
using System.Linq;
namespace Barotrauma.Items.Components
{
@@ -287,7 +285,7 @@ namespace Barotrauma.Items.Components
}
else if (autoTemp)
{
UpdateAutoTemp(10.0f, deltaTime * 2f);
UpdateAutoTemp(2.0f, deltaTime);
}
@@ -300,7 +298,14 @@ namespace Barotrauma.Items.Components
if (!item.HasTag("reactorfuel")) { continue; }
if (fissionRate > 0.0f)
{
item.Condition -= fissionRate / 100.0f * fuelConsumptionRate * deltaTime;
bool isConnectedToFriendlyOutpost = Level.IsLoadedOutpost &&
Item.Submarine?.TeamID == CharacterTeamType.Team1 &&
Item.Submarine.GetConnectedSubs().Any(s => s.Info.IsOutpost && s.TeamID == CharacterTeamType.FriendlyNPC);
if (!isConnectedToFriendlyOutpost)
{
item.Condition -= fissionRate / 100.0f * fuelConsumptionRate * deltaTime;
}
}
fuelLeft += item.ConditionPercentage;
}
@@ -418,7 +423,7 @@ namespace Barotrauma.Items.Components
{
float idealLoad = MaxPowerOutput / minMaxPower.ReactorMaxOutput * loadLeft;
float loadAdjust = MathHelper.Clamp((ratio - 0.5f) * 25 + idealLoad - (turbineOutput / 100 * MaxPowerOutput), -MaxPowerOutput / 100, MaxPowerOutput / 100);
newLoad = MathHelper.Clamp(loadLeft - (expectedPower + output) + loadAdjust, 0, loadLeft);
newLoad = MathHelper.Clamp(loadLeft - (expectedPower - output) + loadAdjust, 0, loadLeft);
}
if (float.IsNegative(newLoad))
@@ -498,7 +503,6 @@ namespace Barotrauma.Items.Components
if (temperature > optimalTemperature.Y)
{
float prevFireTimer = fireTimer;
fireTimer += MathHelper.Lerp(deltaTime * 2.0f, deltaTime, item.Condition / item.MaxCondition);
#if SERVER
if (fireTimer > Math.Min(5.0f, FireDelay / 2) && blameOnBroken?.Character?.SelectedConstruction == item)
@@ -506,9 +510,10 @@ namespace Barotrauma.Items.Components
GameMain.Server.KarmaManager.OnReactorOverHeating(item, blameOnBroken.Character, deltaTime);
}
#endif
if (fireTimer >= FireDelay && prevFireTimer < fireDelay)
if (fireTimer >= FireDelay)
{
new FireSource(item.WorldPosition);
fireTimer = 0.0f;
}
}
else
@@ -349,7 +349,7 @@ namespace Barotrauma.Items.Components
}
}
public void ServerRead(ClientNetObject type, IReadMessage msg, Client c)
public void ServerEventRead(IReadMessage msg, Client c)
{
bool isActive = msg.ReadBoolean();
bool directionalPing = useDirectionalPing;
@@ -394,7 +394,7 @@ namespace Barotrauma.Items.Components
#endif
}
public void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
public void ServerEventWrite(IWriteMessage msg, Client c, NetEntityEvent.IData extraData = null)
{
msg.Write(currentMode == Mode.Active);
if (currentMode == Mode.Active)
@@ -225,7 +225,7 @@ namespace Barotrauma.Items.Components
var dockingConnection = item.Connections.FirstOrDefault(c => c.Name == "toggle_docking");
if (dockingConnection != null)
{
var connectedPorts = item.GetConnectedComponentsRecursive<DockingPort>(dockingConnection);
var connectedPorts = item.GetConnectedComponentsRecursive<DockingPort>(dockingConnection, allowTraversingBackwards: false);
DockingSources.AddRange(connectedPorts.Where(p => p.Item.Submarine != null && !p.Item.Submarine.Info.IsOutpost));
}
}
@@ -271,13 +271,9 @@ namespace Barotrauma.Items.Components
item.CreateClientEvent(this);
correctionTimer = CorrectionDelay;
}
else
#endif
#if SERVER
if (GameMain.Server != null)
{
item.CreateServerEvent(this);
}
item.CreateServerEvent(this);
#endif
networkUpdateTimer = 0.1f;
@@ -2,7 +2,6 @@
using Microsoft.Xna.Framework;
using System;
using System.Globalization;
using System.Xml.Linq;
namespace Barotrauma.Items.Components
{
@@ -11,7 +10,7 @@ namespace Barotrauma.Items.Components
//[power/min]
private float capacity;
private float charge;
private float charge, prevCharge;
//how fast the battery can be recharged
private float maxRechargeSpeed;
@@ -34,7 +33,7 @@ namespace Barotrauma.Items.Components
get { return currPowerOutput; }
private set
{
System.Diagnostics.Debug.Assert(value >= 0.0f);
System.Diagnostics.Debug.Assert(value >= 0.0f, $"Tried to set PowerContainer's output to a negative value ({value})");
currPowerOutput = Math.Max(0, value);
}
}
@@ -140,6 +139,7 @@ namespace Barotrauma.Items.Components
{
IsActive = true;
InitProjSpecific();
prevCharge = Charge;
}
partial void InitProjSpecific();
@@ -171,7 +171,7 @@ namespace Barotrauma.Items.Components
loadReading = powerOut.Grid.Load;
}
item.SendSignal(((int)Math.Round(-CurrPowerOutput)).ToString(), "power_value_out");
item.SendSignal(((int)Math.Round(CurrPowerOutput)).ToString(), "power_value_out");
item.SendSignal(((int)Math.Round(loadReading)).ToString(), "load_value_out");
item.SendSignal(((int)Math.Round(Charge)).ToString(), "charge");
item.SendSignal(((int)Math.Round(Charge / capacity * 100)).ToString(), "charge_%");
@@ -194,6 +194,8 @@ namespace Barotrauma.Items.Components
}
else
{
if (item.Condition <= 0.0f) { return 0.0f; }
float missingCharge = capacity - charge;
float targetRechargeSpeed = rechargeSpeed;
@@ -231,7 +233,7 @@ namespace Barotrauma.Items.Components
if (connection == powerOut)
{
float maxOutput;
float chargeRatio = charge / capacity;
float chargeRatio = prevCharge / capacity;
if (chargeRatio < 0.1f)
{
maxOutput = Math.Max(chargeRatio * 10.0f, 0.0f) * MaxOutPut;
@@ -242,7 +244,7 @@ namespace Barotrauma.Items.Components
}
//Limit max power out to not exceed the charge of the container
maxOutput = Math.Min(maxOutput, charge * 60 / UpdateInterval);
maxOutput = Math.Min(maxOutput, prevCharge * 60 / UpdateInterval);
return new PowerRange(0.0f, maxOutput);
}
@@ -261,18 +263,11 @@ namespace Barotrauma.Items.Components
/// <returns></returns>
public override float GetConnectionPowerOut(Connection connection, float power, PowerRange minMaxPower, float load)
{
if (connection == powerOut)
//Only power out connection can provide power and Max poweroutput can't be negative
if (connection == powerOut && minMaxPower.Max > 0)
{
//Calculate the max power the container can output
float maxPowerOutput = MaxOutPut;
float chargeRatio = charge / capacity;
if (chargeRatio < 0.1f)
{
maxPowerOutput *= Math.Max(chargeRatio * 10.0f, 0.0f);
}
//Set power output based on the relative max power output capabilities and load demand
CurrPowerOutput = MathHelper.Clamp((load - power) / minMaxPower.Max, 0, 1) * maxPowerOutput;
CurrPowerOutput = MathHelper.Clamp((load - power) / minMaxPower.Max, 0, 1) * MinMaxPowerOut(connection, load).Max;
return CurrPowerOutput;
}
return 0.0f;
@@ -292,6 +287,7 @@ namespace Barotrauma.Items.Components
{
//Decrease charge based on how much power is leaving the device
Charge = Math.Clamp(Charge - CurrPowerOutput / 60 * UpdateInterval, 0, Capacity);
prevCharge = Charge;
}
}
@@ -176,23 +176,6 @@ namespace Barotrauma.Items.Components
{
RefreshConnections();
float powerReadingOut = 0;
float loadReadingOut = ExtraLoad;
if (powerLoad < 0)
{
powerReadingOut = -powerLoad;
loadReadingOut = 0;
}
if (powerOut != null && powerOut.Grid != null)
{
powerReadingOut = powerOut.Grid.Power;
loadReadingOut = powerOut.Grid.Load;
}
item.SendSignal(((int)Math.Round(powerReadingOut)).ToString(), "power_value_out");
item.SendSignal(((int)Math.Round(loadReadingOut)).ToString(), "load_value_out");
if (Timing.TotalTime > extraLoadSetTime + 1.0)
{
//Decay the extra load to 0 from either positive or negative
@@ -216,22 +199,36 @@ namespace Barotrauma.Items.Components
ApplyStatusEffects(ActionType.OnActive, deltaTime, null);
//if the item can't be fixed, don't allow it to break
if (!item.Repairables.Any() || !CanBeOverloaded) { return; }
if (prevSentPowerValue != (int)-CurrPowerConsumption || powerSignal == null)
float powerReadingOut = 0;
float loadReadingOut = ExtraLoad;
if (powerLoad < 0)
{
prevSentPowerValue = (int)Math.Round(-CurrPowerConsumption);
powerReadingOut = -powerLoad;
loadReadingOut = 0;
}
if (powerOut != null && powerOut.Grid != null)
{
powerReadingOut = powerOut.Grid.Power;
loadReadingOut = powerOut.Grid.Load;
}
if (prevSentPowerValue != (int)powerReadingOut || powerSignal == null)
{
prevSentPowerValue = (int)Math.Round(powerReadingOut);
powerSignal = prevSentPowerValue.ToString();
}
if (prevSentLoadValue != (int)powerLoad || loadSignal == null)
if (prevSentLoadValue != (int)loadReadingOut || loadSignal == null)
{
prevSentLoadValue = (int)Math.Round(powerLoad);
prevSentLoadValue = (int)Math.Round(loadReadingOut);
loadSignal = prevSentLoadValue.ToString();
}
item.SendSignal(powerSignal, "power_value_out");
item.SendSignal(loadSignal, "load_value_out");
//if the item can't be fixed, don't allow it to break
if (!item.Repairables.Any() || !CanBeOverloaded) { return; }
float maxOverVoltage = Math.Max(OverloadVoltage, 1.0f);
Overload = Voltage > maxOverVoltage;
@@ -187,14 +187,11 @@ namespace Barotrauma.Items.Components
protected void UpdateOnActiveEffects(float deltaTime)
{
if (currPowerConsumption <= 0.0f)
if (currPowerConsumption <= 0.0f && PowerConsumption <= 0.0f)
{
//if the item consumes no power, ignore the voltage requirement and
//apply OnActive statuseffects as long as this component is active
if (PowerConsumption <= 0.0f)
{
ApplyStatusEffects(ActionType.OnActive, deltaTime, null);
}
ApplyStatusEffects(ActionType.OnActive, deltaTime, null);
return;
}
@@ -216,6 +213,11 @@ namespace Barotrauma.Items.Components
powerOnSoundPlayed = false;
}
#endif
if (powerIn == null)
{
//power down the device here if it has no power connection (= receives power from contained battery cells instead of the "normal" power logic)
Voltage -= deltaTime;
}
}
public override void Update(float deltaTime, Camera cam)
@@ -238,7 +240,11 @@ namespace Barotrauma.Items.Components
else if (c.Name == "power_out")
{
powerOut = c;
powerOut.Priority = Priority;
// Connection takes the lowest priority
if (Priority > powerOut.Priority)
{
powerOut.Priority = Priority;
}
}
else if (c.Name == "power")
{
@@ -258,7 +264,11 @@ namespace Barotrauma.Items.Components
#endif
}
powerOut = c;
powerOut.Priority = Priority;
// Connection takes the lowest priority
if (Priority > powerOut.Priority)
{
powerOut.Priority = Priority;
}
}
else
{
@@ -591,7 +601,7 @@ namespace Barotrauma.Items.Components
foreach (Connection con in grid.Connections)
{
Powered device = con.Item.GetComponent<Powered>();
device.GridResolved(con);
device?.GridResolved(con);
}
}
@@ -196,6 +196,13 @@ namespace Barotrauma.Items.Components
set;
}
[Serialize(true, IsPropertySaveable.No)]
public bool FriendlyFire
{
get;
set;
}
private float deactivationTimer;
[Serialize(0f, IsPropertySaveable.No)]
@@ -309,7 +316,7 @@ namespace Barotrauma.Items.Components
{
#if SERVER
launchRot = rotation;
Item.CreateServerEvent(this, new object[] { true }); //true = indicate that this is a launch event
Item.CreateServerEvent(this, new EventData(launch: true));
#endif
}
}
@@ -673,7 +680,7 @@ namespace Barotrauma.Items.Components
{
Unstick();
#if SERVER
item.CreateServerEvent(this);
item.CreateServerEvent(this, new EventData(launch: false));
#endif
}
}
@@ -697,9 +704,9 @@ namespace Barotrauma.Items.Components
return false;
}
if (hits.Contains(target.Body)) { return false; }
if (ShouldIgnoreSubmarineCollision(target, contact))
if (target.Body.UserData is Submarine)
{
return false;
if (ShouldIgnoreSubmarineCollision(ref target, contact)) { return false; }
}
else if (target.Body.UserData is Limb limb)
{
@@ -709,6 +716,10 @@ namespace Barotrauma.Items.Components
limb.body?.ApplyLinearImpulse(item.body.LinearVelocity * item.body.Mass * 0.1f, item.SimPosition);
return false;
}
if (!FriendlyFire && User != null && limb.character.IsFriendly(User))
{
return false;
}
}
else if (target.Body.UserData is Item item)
{
@@ -893,8 +904,8 @@ namespace Barotrauma.Items.Components
#if SERVER
if (GameMain.NetworkMember.IsServer)
{
GameMain.Server?.CreateEntityEvent(item, new object[] { NetEntityEvent.Type.ApplyStatusEffect, actionType, this, targetLimb.character.ID, targetLimb, (ushort)0, item.WorldPosition });
GameMain.Server?.CreateEntityEvent(item, new object[] { NetEntityEvent.Type.ApplyStatusEffect, ActionType.OnImpact, this, targetLimb.character.ID, targetLimb, (ushort)0, item.WorldPosition });
GameMain.Server?.CreateEntityEvent(item, new Item.ApplyStatusEffectEventData(actionType, this, targetLimb.character, targetLimb, null, item.WorldPosition));
GameMain.Server?.CreateEntityEvent(item, new Item.ApplyStatusEffectEventData(ActionType.OnImpact, this, targetLimb.character, targetLimb, null, item.WorldPosition));
}
#endif
}
@@ -905,8 +916,8 @@ namespace Barotrauma.Items.Components
#if SERVER
if (GameMain.NetworkMember.IsServer)
{
GameMain.Server?.CreateEntityEvent(item, new object[] { NetEntityEvent.Type.ApplyStatusEffect, actionType, this, (ushort)0, null, (target.Body.UserData as Entity)?.ID ?? 0, item.WorldPosition });
GameMain.Server?.CreateEntityEvent(item, new object[] { NetEntityEvent.Type.ApplyStatusEffect, ActionType.OnImpact, this, (ushort)0, null, (target.Body.UserData as Entity)?.ID ?? 0, item.WorldPosition });
GameMain.Server?.CreateEntityEvent(item, new Item.ApplyStatusEffectEventData(actionType, this, null, null, target.Body.UserData as Entity, item.WorldPosition));
GameMain.Server?.CreateEntityEvent(item, new Item.ApplyStatusEffectEventData(ActionType.OnImpact, this, null, null, target.Body.UserData as Entity, item.WorldPosition));
}
#endif
}
@@ -952,7 +963,7 @@ namespace Barotrauma.Items.Components
#if SERVER
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsServer)
{
item.CreateServerEvent(this);
item.CreateServerEvent(this, new EventData(launch: false));
}
#endif
item.body.LinearVelocity *= speedMultiplier;
@@ -230,7 +230,7 @@ namespace Barotrauma.Items.Components
{
ApplyStatusEffects(ActionType.OnFailure, 1.0f, CurrentFixer);
#if SERVER
GameMain.Server?.CreateEntityEvent(item, new object[] { NetEntityEvent.Type.ApplyStatusEffect, ActionType.OnFailure, this, CurrentFixer.ID });
GameMain.Server?.CreateEntityEvent(item, new Item.ApplyStatusEffectEventData(ActionType.OnFailure, this, CurrentFixer));
#endif
}
}
@@ -256,10 +256,10 @@ namespace Barotrauma.Items.Components
if (!CheckCharacterSuccess(character, bestRepairItem))
{
GameServer.Log($"{GameServer.CharacterLogName(character)} failed to {(action == FixActions.Sabotage ? "sabotage" : "repair")} {item.Name}", ServerLog.MessageType.ItemInteraction);
GameMain.Server?.CreateEntityEvent(item, new object[] { NetEntityEvent.Type.ApplyStatusEffect, ActionType.OnFailure, this, character.ID });
GameMain.Server?.CreateEntityEvent(item, new Item.ApplyStatusEffectEventData(ActionType.OnFailure, this, character));
if (bestRepairItem != null && bestRepairItem.GetComponent<Holdable>() is Holdable h)
{
GameMain.Server?.CreateEntityEvent(bestRepairItem, new object[] { NetEntityEvent.Type.ApplyStatusEffect, ActionType.OnFailure, h, character.ID });
GameMain.Server?.CreateEntityEvent(bestRepairItem, new Item.ApplyStatusEffectEventData(ActionType.OnFailure, h, character));
}
return false;
@@ -15,6 +15,8 @@ namespace Barotrauma.Items.Components
//the output is sent if both inputs have received a signal within the timeframe
protected float timeFrame;
protected readonly Character[] signalSender = new Character[2];
[Serialize(999999.0f, IsPropertySaveable.Yes, description: "The output of the item is restricted below this value.", alwaysUseInstanceValues: true),
InGameEditable(MinValueFloat = -999999.0f, MaxValueFloat = 999999.0f)]
public float ClampMax
@@ -33,7 +35,7 @@ namespace Barotrauma.Items.Components
[InGameEditable(DecimalCount = 2),
Serialize(0.0f, IsPropertySaveable.Yes, description: "The item must have received signals to both inputs within this timeframe to output the result." +
" If set to 0, the inputs must be received at the same time.", alwaysUseInstanceValues: true)]
" If set to 0, the inputs must be received at the same time.", alwaysUseInstanceValues: true, translationTextTag: "sp.")]
public float TimeFrame
{
get { return timeFrame; }
@@ -71,7 +73,7 @@ namespace Barotrauma.Items.Components
float output = Calculate(receivedSignal[0], receivedSignal[1]);
if (MathUtils.IsValid(output))
{
item.SendSignal(MathHelper.Clamp(output, ClampMin, ClampMax).ToString("G", CultureInfo.InvariantCulture), "signal_out");
item.SendSignal(new Signal(MathHelper.Clamp(output, ClampMin, ClampMax).ToString("G", CultureInfo.InvariantCulture), sender: signalSender[0] ?? signalSender[1]), "signal_out");
}
}
@@ -83,11 +85,13 @@ namespace Barotrauma.Items.Components
{
case "signal_in1":
float.TryParse(signal.value, NumberStyles.Float, CultureInfo.InvariantCulture, out receivedSignal[0]);
signalSender[0] = signal.sender;
timeSinceReceived[0] = 0.0f;
IsActive = true;
break;
case "signal_in2":
float.TryParse(signal.value, NumberStyles.Float, CultureInfo.InvariantCulture, out receivedSignal[1]);
signalSender[1] = signal.sender;
timeSinceReceived[1] = 0.0f;
IsActive = true;
break;
@@ -109,10 +109,23 @@ namespace Barotrauma.Items.Components
return true;
}
private void Write(IWriteMessage msg, object[] extraData)
private readonly struct EventData : IEventData
{
if (extraData == null || extraData.Length < 3) { return; }
msg.WriteRangedInteger((int)extraData[2], 0, Signals.Length - 1);
public readonly int SignalIndex;
public EventData(int signalIndex)
{
SignalIndex = signalIndex;
}
}
public override bool ValidateEventData(NetEntityEvent.IData data)
=> TryExtractEventData<EventData>(data, out _);
private void Write(IWriteMessage msg, NetEntityEvent.IData extraData)
{
var eventData = ExtractEventData<EventData>(extraData);
msg.WriteRangedInteger(eventData.SignalIndex, 0, Signals.Length - 1);
}
}
}
@@ -400,7 +400,7 @@ namespace Barotrauma.Items.Components
}
public void ClientWrite(IWriteMessage msg, object[] extraData = null)
public void ClientEventWrite(IWriteMessage msg, NetEntityEvent.IData extraData = null)
{
#if CLIENT
TriggerRewiringSound();
@@ -8,6 +8,16 @@ namespace Barotrauma.Items.Components
{
partial class CustomInterface : ItemComponent, IClientSerializable, IServerSerializable
{
private readonly struct EventData : IEventData
{
public readonly CustomInterfaceElement BtnElement;
public EventData(CustomInterfaceElement btnElement)
{
BtnElement = btnElement;
}
}
class CustomInterfaceElement : ISerializableEntity
{
public bool ContinuousSignal;
@@ -1,7 +1,6 @@
using FarseerPhysics;
using Microsoft.Xna.Framework;
using System;
using System.Linq;
using System.Xml.Linq;
namespace Barotrauma.Items.Components
@@ -1,13 +1,11 @@
using System.Xml.Linq;
namespace Barotrauma.Items.Components
namespace Barotrauma.Items.Components
{
class NotComponent : ItemComponent
{
private bool signalReceived;
private bool continuousOutput;
[Editable, Serialize(false, IsPropertySaveable.Yes, description: "When enabled, the component continuously outputs \"1\" when it's not receiving a signal.", alwaysUseInstanceValues: true)]
[InGameEditable, Serialize(false, IsPropertySaveable.Yes, description: "When enabled, the component continuously outputs \"1\" when it's not receiving a signal.", alwaysUseInstanceValues: true)]
public bool ContinuousOutput
{
get { return continuousOutput; }
@@ -372,12 +372,12 @@ namespace Barotrauma.Items.Components
IsOn = on;
}
public void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
public void ServerEventWrite(IWriteMessage msg, Client c, NetEntityEvent.IData extraData = null)
{
msg.Write(isOn);
}
public void ClientRead(ServerNetObject type, IReadMessage msg, float _)
public void ClientEventRead(IReadMessage msg, float sendingTime)
{
SetState(msg.ReadBoolean(), true);
}
@@ -68,7 +68,7 @@ namespace Barotrauma.Items.Components
{
foreach (FireSource fireSource in hull.FireSources)
{
if (fireSource.IsInDamageRange(item.WorldPosition, fireSource.DamageRange * 2.0f)) { return true; }
if (fireSource.IsInDamageRange(item.WorldPosition, Math.Max(fireSource.DamageRange * 2.0f, 500.0f))) { return true; }
}
}
@@ -1,7 +1,4 @@
using Microsoft.Xna.Framework;
using System;
using System.Globalization;
using System.Xml.Linq;
using System;
namespace Barotrauma.Items.Components
{
@@ -20,6 +20,8 @@ namespace Barotrauma.Items.Components
private readonly float[] receivedSignal = new float[2];
private readonly float[] timeSinceReceived = new float[2];
protected Character signalSender;
[Serialize(FunctionType.Sin, IsPropertySaveable.No, description: "Which kind of function to run the input through.", alwaysUseInstanceValues: true)]
public FunctionType Function
{
@@ -56,7 +58,7 @@ namespace Barotrauma.Items.Components
{
float angle = (float)Math.Atan2(receivedSignal[1], receivedSignal[0]);
if (!UseRadians) { angle = MathHelper.ToDegrees(angle); }
item.SendSignal(angle.ToString("G", CultureInfo.InvariantCulture), "signal_out");
item.SendSignal(new Signal(angle.ToString("G", CultureInfo.InvariantCulture), sender: signalSender), "signal_out");
}
}
}
@@ -65,6 +67,7 @@ namespace Barotrauma.Items.Components
{
float.TryParse(signal.value, NumberStyles.Float, CultureInfo.InvariantCulture, out float value);
bool sendOutputImmediately = true;
signalSender = signal.sender;
switch (Function)
{
case FunctionType.Sin:
@@ -455,12 +455,7 @@ namespace Barotrauma.Items.Components
#if CLIENT
if (GameMain.NetworkMember != null)
{
GameMain.Client.CreateEntityEvent(item, new object[]
{
NetEntityEvent.Type.ComponentState,
item.GetComponentIndex(this),
nodes.Count
});
item.CreateClientEvent(this, new ClientEventData(nodes.Count));
}
#endif
}
@@ -482,12 +477,7 @@ namespace Barotrauma.Items.Components
#if CLIENT
if (GameMain.NetworkMember != null)
{
GameMain.Client.CreateEntityEvent(item, new object[]
{
NetEntityEvent.Type.ComponentState,
item.GetComponentIndex(this),
nodes.Count
});
item.CreateClientEvent(this, new ClientEventData(nodes.Count));
}
#endif
}
@@ -49,8 +49,6 @@ namespace Barotrauma.Items.Components
private ChargingState currentChargingState;
private float currentBarrelSpin = 0f;
private readonly List<Item> activeProjectiles = new List<Item>();
public IEnumerable<Item> ActiveProjectiles => activeProjectiles;
@@ -330,10 +328,10 @@ namespace Barotrauma.Items.Components
public override void OnMapLoaded()
{
base.OnMapLoaded();
FindLightComponent();
if (loadedRotationLimits.HasValue) { RotationLimits = loadedRotationLimits.Value; }
if (loadedBaseRotation.HasValue) { BaseRotation = loadedBaseRotation.Value; }
targetRotation = rotation;
FindLightComponent();
UpdateTransformedBarrelPos();
}
@@ -736,6 +734,16 @@ namespace Barotrauma.Items.Components
return true;
}
private readonly struct EventData : IEventData
{
public readonly Item Projectile;
public EventData(Item projectile)
{
Projectile = projectile;
}
}
private void Launch(Item projectile, Character user = null, float? launchRotation = null, float tinkeringStrength = 0f)
{
reload = reloadTime;
@@ -749,7 +757,7 @@ namespace Barotrauma.Items.Components
if (projectile != null)
{
activeProjectiles.Add(projectile);
projectile.Drop(null);
projectile.Drop(null, setTransform: false);
if (projectile.body != null)
{
projectile.body.Dir = 1.0f;
@@ -787,12 +795,11 @@ namespace Barotrauma.Items.Components
}
}
if (projectile.Container != null) { projectile.Container.RemoveContained(projectile); }
}
if (GameMain.NetworkMember != null && GameMain.NetworkMember.IsServer)
{
GameMain.NetworkMember.CreateEntityEvent(item, new object[] { NetEntityEvent.Type.ComponentState, item.GetComponentIndex(this), projectile });
projectile.Container?.RemoveContained(projectile);
}
#if SERVER
item.CreateServerEvent(this, new EventData(projectile));
#endif
ApplyStatusEffects(ActionType.OnUse, 1.0f, user: user);
LaunchProjSpecific();
@@ -1630,11 +1637,11 @@ namespace Barotrauma.Items.Components
}
}
public void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
public void ServerEventWrite(IWriteMessage msg, Client c, NetEntityEvent.IData extraData = null)
{
if (extraData.Length > 2)
if (TryExtractEventData(extraData, out EventData eventData))
{
msg.Write(!(extraData[2] is Item item) ? ushort.MaxValue : item.ID);
msg.Write(eventData.Projectile.ID);
msg.WriteRangedSingle(MathHelper.Clamp(rotation, minRotation, maxRotation), minRotation, maxRotation, 16);
}
else
@@ -540,16 +540,16 @@ namespace Barotrauma.Items.Components
Variant = loadedVariant;
}
}
public override void ServerWrite(IWriteMessage msg, Client c, object[] extraData = null)
public override void ServerEventWrite(IWriteMessage msg, Client c, NetEntityEvent.IData extraData = null)
{
msg.Write((byte)Variant);
base.ServerWrite(msg, c, extraData);
base.ServerEventWrite(msg, c, extraData);
}
public override void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
public override void ClientEventRead(IReadMessage msg, float sendingTime)
{
Variant = (int)msg.ReadByte();
base.ClientRead(type, msg, sendingTime);
base.ClientEventRead(msg, sendingTime);
}
}