Barotrauma/BarotraumaShared/Source/Items/Components/ItemComponent.cs
This commit is contained in:
juanjp600
2017-12-20 19:46:53 -03:00
75 changed files with 2109 additions and 596 deletions
@@ -9,6 +9,8 @@ namespace Barotrauma
public enum Animation { None, Climbing, UsingConstruction, Struggle, CPR };
public Animation Anim;
public LimbType GrabLimb;
protected Character character;
protected float walkSpeed, swimSpeed;
@@ -20,6 +20,7 @@ namespace Barotrauma
private float thighTorque;
private float cprAnimState;
private float cprPump;
private float inWaterTimer;
private bool swimming;
@@ -872,7 +873,34 @@ namespace Barotrauma
character.SelectedConstruction = null;
IgnorePlatforms = false;
}
else if (character.SelectedCharacter != null && !character.SelectedCharacter.AllowInput)
{
Limb targetLeftHand = character.SelectedCharacter.AnimController.GetLimb(LimbType.LeftHand);
Limb targetRightHand = character.SelectedCharacter.AnimController.GetLimb(LimbType.RightHand);
Limb targetTorso = character.SelectedCharacter.AnimController.GetLimb(LimbType.Torso);
if (character.SelectedCharacter.AnimController.Dir != Dir)
character.SelectedCharacter.AnimController.Flip();
targetTorso.pullJoint.Enabled = true;
targetTorso.pullJoint.WorldAnchorB = torso.SimPosition + (Vector2.UnitX * -Dir) * 0.2f;
targetTorso.pullJoint.MaxForce = 5000.0f;
if (!targetLeftHand.IsSevered)
{
targetLeftHand.pullJoint.Enabled = true;
targetLeftHand.pullJoint.WorldAnchorB = torso.SimPosition + (new Vector2(1 * Dir, 1)) * 0.2f;
targetLeftHand.pullJoint.MaxForce = 5000.0f;
}
if (!targetRightHand.IsSevered)
{
targetRightHand.pullJoint.Enabled = true;
targetRightHand.pullJoint.WorldAnchorB = torso.SimPosition + (new Vector2(1 * Dir, 1)) * 0.2f;
targetRightHand.pullJoint.MaxForce = 5000.0f;
}
character.SelectedCharacter.AnimController.IgnorePlatforms = true;
}
}
private void UpdateCPR(float deltaTime)
@@ -883,11 +911,16 @@ namespace Barotrauma
return;
}
Character target = character.SelectedCharacter;
Crouching = true;
Vector2 diff = character.SelectedCharacter.SimPosition - character.SimPosition;
var targetHead = character.SelectedCharacter.AnimController.GetLimb(LimbType.Head);
Vector2 diff = target.SimPosition - character.SimPosition;
Limb targetHead = target.AnimController.GetLimb(LimbType.Head);
Limb targetTorso = target.AnimController.GetLimb(LimbType.Torso);
Limb head = GetLimb(LimbType.Head);
Limb torso = GetLimb(LimbType.Torso);
Vector2 headDiff = targetHead == null ? diff : targetHead.SimPosition - character.SimPosition;
targetMovement = new Vector2(diff.X, 0.0f);
@@ -895,21 +928,98 @@ namespace Barotrauma
UpdateStanding();
Vector2 handPos = character.SelectedCharacter.AnimController.GetLimb(LimbType.Torso).SimPosition + Vector2.UnitY * 0.2f;
Vector2 handPos = targetTorso.SimPosition + Vector2.UnitY * 0.2f;
Grab(handPos, handPos);
float yPos = (float)Math.Sin(cprAnimState) * 0.1f;
cprAnimState += deltaTime * 8.0f;
Vector2 colliderPos = GetColliderBottom();
var head = GetLimb(LimbType.Head);
head.pullJoint.WorldAnchorB = new Vector2(targetHead.SimPosition.X, targetHead.SimPosition.Y + 0.6f + yPos);
head.pullJoint.Enabled = true;
if (GameMain.Client == null) //Serverside code
{
if (target.Bleeding <= 0.5f && target.Oxygen <= 0.0f) //If they're bleeding too hard CPR will hurt them
{
target.Oxygen += deltaTime * 0.5f; //Stabilize them
}
}
int skill = character.GetSkillLevel("Medical");
if (cprAnimState % 17 > 15.0f)
{
float yPos = (float)Math.Sin(cprAnimState) * 0.2f;
head.pullJoint.WorldAnchorB = new Vector2(targetHead.SimPosition.X, targetHead.SimPosition.Y + 0.3f + yPos);
head.pullJoint.Enabled = true;
torso.pullJoint.WorldAnchorB = new Vector2(torso.SimPosition.X, colliderPos.Y + (TorsoPosition - 0.2f));
torso.pullJoint.Enabled = true;
if (GameMain.Client == null) //Serverside code
{
float cpr = skill / 2.0f; //Max possible oxygen addition is 20 per second
character.Oxygen -= (30.0f - cpr) * deltaTime; //Worse skill = more oxygen required
if (character.Oxygen > 0.0f) //we didn't suffocate yet did we
target.Oxygen += cpr * deltaTime;
//DebugConsole.NewMessage("CPR Us: " + character.Oxygen + " Them: " + target.Oxygen + " How good we are: restore " + cpr + " use " + (30.0f - cpr), Color.Aqua);
}
}
else
{
head.pullJoint.WorldAnchorB = new Vector2(targetHead.SimPosition.X, targetHead.SimPosition.Y + 0.8f);
head.pullJoint.Enabled = true;
torso.pullJoint.WorldAnchorB = new Vector2(torso.SimPosition.X, colliderPos.Y + (TorsoPosition - 0.1f));
torso.pullJoint.Enabled = true;
if (cprPump >= 1)
{
torso.body.ApplyForce(new Vector2(0, -1000f));
targetTorso.body.ApplyForce(new Vector2(0, -1000f));
cprPump = 0;
if (target.Bleeding <= 0.5f && target.Health <= 0.0f && !target.IsDead) //Have a chance to revive them to 2 HP if they were damaged.
{
if (GameMain.Client == null) //Serverside code
{
float reviveChance = (cprAnimState % 17) * (skill / 50.0f); //~5% max chance for 10 skill, ~50% max chance for 100 skill
float rng = Rand.Int(100, Rand.RandSync.Server);
//DebugConsole.NewMessage("CPR Pump cprAnimState: " + (cprAnimState % 17) + " revive chance: " + reviveChance + " rng: " + rng, Color.Aqua);
if (rng <= reviveChance) //HOLY CRAP YOU SAVED HIM!!!
{
target.Oxygen = Math.Max(target.Oxygen, 10.0f);
target.Health = 2.0f;
Anim = Animation.None;
return;
}
}
}
else if (target.Bleeding > 0.5f || skill < 50) //We will hurt them if they're bleeding or we suck
{
//If not bleeding: 10% skill causes 0.8 damage per pump, 40% skill causes only 0.2
if (target.Bleeding <= 0.5f)
target.AddDamage(CauseOfDeath.Damage, (50 - skill) * 0.02f, character);
else //If bleeding: 2 HP damage per pump. Basically speeds up their death. Don't pump bleeding people!
{
target.AddDamage(CauseOfDeath.Bloodloss, 1.0f, character);
#if CLIENT
SoundPlayer.PlayDamageSound(DamageSoundType.LimbBlunt, 25.0f, targetTorso.body);
for (int i = 0; i < 4; i++)
{
var blood = GameMain.ParticleManager.CreateParticle(inWater ? "waterblood" : "blood", targetTorso.WorldPosition, Rand.Vector(10.0f), 0.0f, target.AnimController.CurrentHull);
}
#endif
}
}
}
cprPump += deltaTime;
}
cprAnimState += deltaTime;
}
public override void DragCharacter(Character target)
{
if (target == null) return;
Limb torso = GetLimb(LimbType.Torso);
Limb leftHand = GetLimb(LimbType.LeftHand);
Limb rightHand = GetLimb(LimbType.RightHand);
@@ -922,31 +1032,34 @@ namespace Barotrauma
for (int i = 0; i < 2; i++)
{
Limb targetLimb = target.AnimController.GetLimb(LimbType.Torso);
Limb targetLimb = target.AnimController.GetLimb(GrabLimb);
if (i == 0)
if (targetLimb == null || targetLimb.IsSevered)
{
if (!targetLeftHand.IsSevered)
targetLimb = target.AnimController.GetLimb(LimbType.Torso);
if (i == 0)
{
targetLimb = targetLeftHand;
if (!targetLeftHand.IsSevered)
{
targetLimb = targetLeftHand;
}
else if (!targetRightHand.IsSevered)
{
targetLimb = targetRightHand;
}
}
else if (!targetRightHand.IsSevered)
else
{
targetLimb = targetRightHand;
if (!targetRightHand.IsSevered)
{
targetLimb = targetRightHand;
}
else if (!targetLeftHand.IsSevered)
{
targetLimb = targetLeftHand;
}
}
}
else
{
if (!targetRightHand.IsSevered)
{
targetLimb = targetRightHand;
}
else if (!targetLeftHand.IsSevered)
{
targetLimb = targetLeftHand;
}
}
Limb pullLimb = i == 0 ? leftHand : rightHand;
if (i == 1 && inWater)
@@ -958,12 +1071,32 @@ namespace Barotrauma
Vector2 diff = ConvertUnits.ToSimUnits(targetLimb.WorldPosition - pullLimb.WorldPosition);
pullLimb.pullJoint.Enabled = true;
pullLimb.pullJoint.WorldAnchorB = pullLimb.SimPosition + diff;
pullLimb.pullJoint.MaxForce = 10000.0f;
if (targetLimb.type == LimbType.Torso)
{
pullLimb.pullJoint.WorldAnchorB = targetLimb.SimPosition;
pullLimb.pullJoint.MaxForce = 5000.0f;
targetMovement *= 0.7f; //Carrying people like that takes a lot of effort.
if (target.AnimController.Dir != Dir)
target.AnimController.Flip();
}
else
{
pullLimb.pullJoint.WorldAnchorB = pullLimb.SimPosition + diff;
pullLimb.pullJoint.MaxForce = 5000.0f;
}
targetLimb.pullJoint.Enabled = true;
targetLimb.pullJoint.WorldAnchorB = targetLimb.SimPosition - diff;
targetLimb.pullJoint.MaxForce = 10000.0f;
if (targetLimb.type == LimbType.Torso)
{
targetLimb.pullJoint.WorldAnchorB = torso.SimPosition + (Vector2.UnitX * Dir) * 0.6f;
targetLimb.pullJoint.MaxForce = 300.0f;
}
else
{
targetLimb.pullJoint.WorldAnchorB = targetLimb.SimPosition - diff;
targetLimb.pullJoint.MaxForce = 5000.0f;
}
target.AnimController.movement = -diff;
}
@@ -1011,8 +1144,6 @@ namespace Barotrauma
public override void HoldItem(float deltaTime, Item item, Vector2[] handlePos, Vector2 holdPos, Vector2 aimPos, bool aim, float holdAngle)
{
Holdable holdable = item.GetComponent<Holdable>();
if (character.IsUnconscious || character.Stun > 0.0f) aim = false;
//calculate the handle positions
@@ -1030,7 +1161,6 @@ namespace Barotrauma
bool usingController = character.SelectedConstruction != null && character.SelectedConstruction.GetComponent<Controller>() != null;
float itemAngle;
if (Anim != Animation.Climbing && !usingController && character.Stun <= 0.0f && aim && itemPos != Vector2.Zero)
{
@@ -1042,6 +1172,7 @@ namespace Barotrauma
itemAngle = (torso.body.Rotation + holdAngle * Dir);
Holdable holdable = item.GetComponent<Holdable>();
if (holdable.ControlPose)
{
head.body.SmoothRotate(itemAngle);
@@ -7,6 +7,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using Barotrauma.Items.Components;
using FarseerPhysics.Dynamics;
namespace Barotrauma
{
@@ -138,6 +139,27 @@ namespace Barotrauma
return info != null && !string.IsNullOrWhiteSpace(info.Name) ? info.Name : SpeciesName;
}
}
//Only used by server logs to determine "true identity" of the player for cases when they're disguised
public string LogName
{
get
{
return info != null && !string.IsNullOrWhiteSpace(info.Name) ? info.Name + (info.DisplayName != info.Name ? " (as " + info.DisplayName + ")" : "") : SpeciesName;
}
}
private float hideFaceTimer;
public bool HideFace
{
get
{
return hideFaceTimer > 0.0f;
}
set
{
hideFaceTimer = MathHelper.Clamp(hideFaceTimer + (value ? 1.0f : -0.5f), 0.0f, 10.0f);
}
}
public string ConfigPath
{
@@ -591,7 +613,7 @@ namespace Barotrauma
{
AnimController = new HumanoidAnimController(this, doc.Root.Element("ragdoll"));
AnimController.TargetDir = Direction.Right;
inventory = new CharacterInventory(16, this);
inventory = new CharacterInventory(17, this);
}
else
{
@@ -961,6 +983,56 @@ namespace Barotrauma
}
}
}
public bool CanSeeCharacter(Character character)
{
Limb selfLimb = AnimController.GetLimb(LimbType.Head);
if (selfLimb == null) selfLimb = AnimController.GetLimb(LimbType.Torso);
if (selfLimb == null) selfLimb = AnimController.Limbs[0];
Limb targetLimb = character.AnimController.GetLimb(LimbType.Head);
if (targetLimb == null) targetLimb = character.AnimController.GetLimb(LimbType.Torso);
if (targetLimb == null) targetLimb = character.AnimController.Limbs[0];
if (selfLimb != null && targetLimb != null)
{
Vector2 diff = ConvertUnits.ToSimUnits(targetLimb.WorldPosition - selfLimb.WorldPosition);
Body closestBody = null;
//both inside the same sub (or both outside)
//OR the we're inside, the other character outside
if (character.Submarine == Submarine || character.Submarine == null)
{
closestBody = Submarine.CheckVisibility(selfLimb.SimPosition, selfLimb.SimPosition + diff);
if (closestBody == null) return true;
}
//we're outside, the other character inside
else if (Submarine == null)
{
closestBody = Submarine.CheckVisibility(targetLimb.SimPosition, targetLimb.SimPosition - diff);
if (closestBody == null) return true;
}
//both inside different subs
else
{
closestBody = Submarine.CheckVisibility(selfLimb.SimPosition, selfLimb.SimPosition + diff);
if (closestBody != null && closestBody.UserData is Structure)
{
if (((Structure)closestBody.UserData).CastShadow) return false;
}
closestBody = Submarine.CheckVisibility(targetLimb.SimPosition, targetLimb.SimPosition - diff);
if (closestBody == null) return true;
}
Structure wall = closestBody.UserData as Structure;
return wall == null || !wall.CastShadow;
}
else
{
return false;
}
}
public bool HasEquippedItem(Item item)
{
@@ -1311,7 +1383,7 @@ namespace Barotrauma
findFocusedTimer -= deltaTime;
}
if (SelectedCharacter != null && IsKeyHit(InputType.Select))
if (SelectedCharacter != null && focusedItem == null && IsKeyHit(InputType.Select)) //Let people use ladders and buttons and stuff when dragging chars
{
DeselectCharacter();
}
@@ -1379,6 +1451,8 @@ namespace Barotrauma
public virtual void Update(float deltaTime, Camera cam)
{
UpdateProjSpecific(deltaTime, cam);
if (GameMain.Client != null && this == Controlled && !isSynced) return;
if (!Enabled) return;
@@ -1409,6 +1483,8 @@ namespace Barotrauma
item.Submarine = Submarine;
}
}
HideFace = false;
if (isDead) return;
@@ -1465,26 +1541,42 @@ namespace Barotrauma
}
}
//Skip health effects as critical health handles it differently
if (IsUnconscious)
{
UpdateUnconscious(deltaTime);
return;
}
//Do ragdoll shenanigans before Stun because it's still technically a stun, innit? Less network updates for us!
if (IsForceRagdolled)
IsRagdolled = IsForceRagdolled;
else if (!IsRagdolled || AnimController.Collider.LinearVelocity.Length() < 1f) //Keep us ragdolled if we were forced or we're too speedy to unragdoll
else if ((GameMain.Server == null || GameMain.Server.AllowRagdollButton) && (!IsRagdolled || AnimController.Collider.LinearVelocity.Length() < 1f)) //Keep us ragdolled if we were forced or we're too speedy to unragdoll
IsRagdolled = IsKeyDown(InputType.Ragdoll); //Handle this here instead of Control because we can stop being ragdolled ourselves
//Health effects
if (needsAir) UpdateOxygen(deltaTime);
Health -= bleeding * deltaTime;
Bleeding -= BleedingDecreaseSpeed * deltaTime;
if (health <= minHealth) Kill(CauseOfDeath.Bloodloss);
if (!IsDead) LockHands = false;
//ragdoll button
if (IsRagdolled)
{
if (AnimController is HumanoidAnimController) ((HumanoidAnimController)AnimController).Crouching = false;
if(GameMain.Server != null)
GameMain.Server.CreateEntityEvent(this, new object[] { NetEntityEvent.Type.Status });
AnimController.ResetPullJoints();
selectedConstruction = null;
return;
}
//AI and control stuff
Control(deltaTime, cam);
if (controlled != this && (!(this is AICharacter) || IsRemotePlayer))
{
@@ -1497,28 +1589,18 @@ namespace Barotrauma
selectedConstruction = null;
}
if (SelectedCharacter != null && AnimController.Anim == AnimController.Animation.CPR)
{
if (GameMain.Client == null) SelectedCharacter.Oxygen += (GetSkillLevel("Medical") / 10.0f) * deltaTime;
}
UpdateSightRange();
if (aiTarget != null) aiTarget.SoundRange = 0.0f;
lowPassMultiplier = MathHelper.Lerp(lowPassMultiplier, 1.0f, 0.1f);
if (needsAir) UpdateOxygen(deltaTime);
Health -= bleeding * deltaTime;
Bleeding -= BleedingDecreaseSpeed * deltaTime;
if (health <= minHealth) Kill(CauseOfDeath.Bloodloss);
if (!IsDead) LockHands = false;
//CPR stuff is handled in the UpdateCPR function in HumanoidAnimController
}
partial void UpdateControlled(float deltaTime, Camera cam);
partial void UpdateProjSpecific(float deltaTime, Camera cam);
private void UpdateOxygen(float deltaTime)
{
float prevOxygen = oxygen;
@@ -1552,12 +1634,17 @@ namespace Barotrauma
AnimController.ResetPullJoints();
selectedConstruction = null;
if (oxygen <= 0.0f) Oxygen -= deltaTime * 0.5f;
Oxygen -= deltaTime * 0.5f; //We're critical - our heart stopped!
if (health <= 0.0f)
if (health <= 0.0f) //Critical health - use current state for crit time
{
AddDamage(bleeding > 0.5f ? CauseOfDeath.Bloodloss : CauseOfDeath.Damage, Math.Max(bleeding, 1.0f) * deltaTime, null);
}
else //Keep on bleedin'
{
Health -= bleeding * deltaTime;
Bleeding -= BleedingDecreaseSpeed * deltaTime;
}
}
private void UpdateSightRange()
@@ -1634,7 +1721,7 @@ namespace Barotrauma
var attackingCharacter = attacker as Character;
if (attackingCharacter != null && attackingCharacter.AIController == null)
{
GameServer.Log(Name + " attacked by " + attackingCharacter.Name+". Damage: "+attackResult.Damage+" Bleeding damage: "+attackResult.Bleeding, ServerLog.MessageType.Attack);
GameServer.Log(LogName + " attacked by " + attackingCharacter.LogName +". Damage: "+attackResult.Damage+" Bleeding damage: "+attackResult.Bleeding, ServerLog.MessageType.Attack);
}
if (GameMain.Client == null &&
@@ -1799,7 +1886,7 @@ namespace Barotrauma
AnimController.Frozen = false;
GameServer.Log(Name+" has died (Cause of death: "+causeOfDeath+")", ServerLog.MessageType.Attack);
GameServer.Log(LogName+" has died (Cause of death: "+causeOfDeath+")", ServerLog.MessageType.Attack);
if (OnDeath != null) OnDeath(this, causeOfDeath);
@@ -12,7 +12,38 @@ namespace Barotrauma
partial class CharacterInfo
{
public string Name;
public string DisplayName
{
get
{
string disguiseName = "?";
if (Character == null || !Character.HideFace)
{
return Name;
}
if (Character.Inventory != null)
{
int cardSlotIndex = Character.Inventory.FindLimbSlot(InvSlotType.Card);
if (cardSlotIndex < 0) return disguiseName;
var idCard = Character.Inventory.Items[cardSlotIndex];
if (idCard == null) return disguiseName;
//Disguise as the ID card name if it's equipped
string[] readTags = idCard.Tags.Split(',');
foreach (string tag in readTags)
{
string[] s = tag.Split(':');
if (s[0] == "name")
{
return s[1];
}
}
}
return disguiseName;
}
}
public Character Character;
public readonly string File;
@@ -325,7 +325,7 @@ namespace Barotrauma
break;
case ClientNetObject.ENTITY_STATE:
int eventType = msg.ReadRangedInteger(0,2);
int eventType = msg.ReadRangedInteger(0,3);
switch (eventType)
{
case 0:
@@ -357,6 +357,9 @@ namespace Barotrauma
Kill(lastAttackCauseOfDeath);
}
break;
case 3:
AnimController.GrabLimb = (LimbType)msg.ReadUInt16();
break;
}
break;
}
@@ -436,6 +439,7 @@ namespace Barotrauma
if (AnimController is HumanoidAnimController)
{
tempBuffer.Write(((HumanoidAnimController)AnimController).Crouching);
tempBuffer.Write((UInt16)AnimController.GrabLimb);
}
bool hasAttackLimb = AnimController.Limbs.Any(l => l != null && l.attack != null);
@@ -534,6 +538,8 @@ namespace Barotrauma
msg.WriteRangedSingle(MathHelper.Clamp(Stun, 0.0f, MaxStun), 0.0f, MaxStun, 8);
}
msg.Write(IsRagdolled);
msg.Write(HuskInfectionState > 0.0f);
}
}
@@ -130,6 +130,10 @@ namespace Barotrauma
{
item.AddTag(s);
}
item.AddTag("name:" + character.Name);
item.AddTag("job:" + Name);
if (!string.IsNullOrWhiteSpace(spawnPoint.IdCardDesc))
item.Description = spawnPoint.IdCardDesc;
}
if (parentItem != null) parentItem.Combine(item);
File diff suppressed because it is too large Load Diff
@@ -10,7 +10,7 @@ namespace Barotrauma
[Flags]
public enum InvSlotType
{
None = 0, Any = 1, RightHand = 2, LeftHand = 4, Head = 8, Torso = 16, Legs = 32, Face=64
None = 0, Any = 1, RightHand = 2, LeftHand = 4, Head = 8, Torso = 16, Legs = 32, Face=64, Card=128
};
partial class CharacterInventory : Inventory
@@ -18,7 +18,7 @@ namespace Barotrauma
private Character character;
public static InvSlotType[] limbSlots = new InvSlotType[] {
InvSlotType.Head, InvSlotType.Torso, InvSlotType.Legs, InvSlotType.LeftHand, InvSlotType.RightHand, InvSlotType.Face,
InvSlotType.Head, InvSlotType.Torso, InvSlotType.Legs, InvSlotType.LeftHand, InvSlotType.RightHand, InvSlotType.Face, InvSlotType.Card,
InvSlotType.Any, InvSlotType.Any, InvSlotType.Any, InvSlotType.Any, InvSlotType.Any,
InvSlotType.Any, InvSlotType.Any, InvSlotType.Any, InvSlotType.Any, InvSlotType.Any};
@@ -699,12 +699,12 @@ namespace Barotrauma.Items.Components
if (docked)
{
if (item.Submarine != null && dockingTarget?.item?.Submarine != null)
GameServer.Log(sender.Name + " docked " + item.Submarine.Name + " to " + dockingTarget.item.Submarine.Name, ServerLog.MessageType.ItemInteraction);
GameServer.Log(sender.LogName + " docked " + item.Submarine.Name + " to " + dockingTarget.item.Submarine.Name, ServerLog.MessageType.ItemInteraction);
}
else
{
if (item.Submarine != null && prevDockingTarget?.item?.Submarine != null)
GameServer.Log(sender.Name + " undocked " + item.Submarine.Name + " from " + prevDockingTarget.item.Submarine.Name, ServerLog.MessageType.ItemInteraction);
GameServer.Log(sender.LogName + " undocked " + item.Submarine.Name + " from " + prevDockingTarget.item.Submarine.Name, ServerLog.MessageType.ItemInteraction);
}
}
}
@@ -13,7 +13,7 @@ using Barotrauma.Lights;
namespace Barotrauma.Items.Components
{
partial class Door : ItemComponent, IDrawableComponent, IServerSerializable
partial class Door : Pickable, IDrawableComponent, IServerSerializable
{
private Gap linkedGap;
@@ -203,12 +203,13 @@ namespace Barotrauma.Items.Components
#endif
}
public override bool Pick(Character picker)
public override bool OnPicked(Character picker)
{
isOpen = !isOpen;
return true;
SetState(predictedState == null ? !isOpen : !predictedState.Value, false, true); //crowbar function
#if CLIENT
PlaySound(ActionType.OnPicked, item.WorldPosition);
#endif
return false;
}
public override bool Select(Character character)
@@ -419,7 +420,7 @@ namespace Barotrauma.Items.Components
bool newState = predictedState == null ? isOpen : predictedState.Value;
if (sender != null && wasOpen != newState)
{
GameServer.Log(sender.Name + (newState ? " opened " : " closed ") + item.Name, ServerLog.MessageType.ItemInteraction);
GameServer.Log(sender.LogName + (newState ? " opened " : " closed ") + item.Name, ServerLog.MessageType.ItemInteraction);
}
}
@@ -184,13 +184,13 @@ namespace Barotrauma.Items.Components
item.SetTransform(rightHand.SimPosition, 0.0f);
}
bool alreadySelected = character.HasSelectedItem(item);
if (picker.TrySelectItem(item))
bool alreadySelected = character.HasEquippedItem(item);
if (picker.TrySelectItem(item) || picker.HasEquippedItem(item))
{
item.body.Enabled = true;
IsActive = true;
if (!alreadySelected) GameServer.Log(character.Name + " equipped " + item.Name, ServerLog.MessageType.ItemInteraction);
if (!alreadySelected) GameServer.Log(character.LogName + " equipped " + item.Name, ServerLog.MessageType.ItemInteraction);
}
}
@@ -200,7 +200,7 @@ namespace Barotrauma.Items.Components
picker.DeselectItem(item);
GameServer.Log(character.Name + " unequipped " + item.Name, ServerLog.MessageType.ItemInteraction);
GameServer.Log(character.LogName + " unequipped " + item.Name, ServerLog.MessageType.ItemInteraction);
item.body.Enabled = false;
IsActive = false;
@@ -224,7 +224,7 @@ namespace Barotrauma.Items.Components
}
}
protected override bool OnPicked(Character picker)
public override bool OnPicked(Character picker)
{
if (base.OnPicked(picker))
{
@@ -235,7 +235,7 @@ namespace Barotrauma.Items.Components
item.CreateServerEvent(this);
if (picker != null)
{
Networking.GameServer.Log(picker.Name + " detached " + item.Name + " from a wall", ServerLog.MessageType.ItemInteraction);
Networking.GameServer.Log(picker.LogName + " detached " + item.Name + " from a wall", ServerLog.MessageType.ItemInteraction);
}
}
return true;
@@ -290,7 +290,7 @@ namespace Barotrauma.Items.Components
if (GameMain.Server != null)
{
item.CreateServerEvent(this);
GameServer.Log(character.Name + " attached " + item.Name+" to a wall", ServerLog.MessageType.ItemInteraction);
GameServer.Log(character.LogName + " attached " + item.Name+" to a wall", ServerLog.MessageType.ItemInteraction);
}
item.Drop();
}
@@ -308,7 +308,7 @@ namespace Barotrauma.Items.Components
public override void Update(float deltaTime, Camera cam)
{
if (item.body == null || !item.body.Enabled) return;
if (picker == null || !picker.HasSelectedItem(item))
if (picker == null || !picker.HasEquippedItem(item))
{
IsActive = false;
return;
@@ -320,7 +320,37 @@ namespace Barotrauma.Items.Components
item.Submarine = picker.Submarine;
picker.AnimController.HoldItem(deltaTime, item, handlePos, holdPos, aimPos, picker.IsKeyDown(InputType.Aim), holdAngle);
if (picker.HasSelectedItem(item))
{
picker.AnimController.HoldItem(deltaTime, item, handlePos, holdPos, aimPos, picker.IsKeyDown(InputType.Aim), holdAngle);
}
else
{
Limb equipLimb = null;
if (picker.Inventory.IsInLimbSlot(item, InvSlotType.Face) || picker.Inventory.IsInLimbSlot(item, InvSlotType.Head))
{
equipLimb = picker.AnimController.GetLimb(LimbType.Head);
}
else if (picker.Inventory.IsInLimbSlot(item, InvSlotType.Torso))
{
equipLimb = picker.AnimController.GetLimb(LimbType.Torso);
}
else if (picker.Inventory.IsInLimbSlot(item, InvSlotType.Legs))
{
equipLimb = picker.AnimController.GetLimb(LimbType.Waist);
}
if (equipLimb != null)
{
float itemAngle = (equipLimb.Rotation + holdAngle * picker.AnimController.Dir);
Matrix itemTransfrom = Matrix.CreateRotationZ(equipLimb.Rotation);
Vector2 transformedHandlePos = Vector2.Transform(handlePos[0], itemTransfrom);
item.body.ResetDynamics();
item.SetTransform(equipLimb.SimPosition - transformedHandlePos, itemAngle);
}
}
}
protected void Flip(Item item)
@@ -137,7 +137,7 @@ namespace Barotrauma.Items.Components
}
else
{
ac.HoldItem(deltaTime, item, handlePos, new Vector2(hitPos, 0.0f), aimPos, false, holdAngle);
ac.HoldItem(deltaTime, item, handlePos, holdPos, aimPos, false, holdAngle);
}
}
else
@@ -255,12 +255,12 @@ namespace Barotrauma.Items.Components
{
GameMain.Server.CreateEntityEvent(item, new object[] { Networking.NetEntityEvent.Type.ApplyStatusEffect, ActionType.OnUse, targetCharacter.ID });
string logStr = picker?.Name + " used " + item.Name;
string logStr = picker?.LogName + " used " + item.Name;
if (item.ContainedItems != null && item.ContainedItems.Length > 0)
{
logStr += "(" + string.Join(", ", item.ContainedItems.Select(i => i?.Name)) + ")";
}
logStr += " on " + targetCharacter + ".";
logStr += " on " + targetCharacter.LogName + ".";
Networking.GameServer.Log(logStr, Networking.ServerLog.MessageType.Attack);
}
@@ -70,7 +70,7 @@ namespace Barotrauma.Items.Components
}
}
protected virtual bool OnPicked(Character picker)
public virtual bool OnPicked(Character picker)
{
if (picker.Inventory.TryPutItem(item, picker, allowedSlots))
{
@@ -89,6 +89,7 @@ namespace Barotrauma.Items.Components
#if CLIENT
if (!GameMain.Instance.LoadingScreenOpen && picker == Character.Controlled) GUI.PlayUISound(GUISoundType.PickItem);
PlaySound(ActionType.OnPicked, item.WorldPosition);
#endif
return true;
@@ -97,7 +97,7 @@ namespace Barotrauma.Items.Components
Vector2 throwVector = picker.CursorWorldPosition - picker.WorldPosition;
throwVector = Vector2.Normalize(throwVector);
GameServer.Log(picker.Name + " threw " + item.Name, ServerLog.MessageType.ItemInteraction);
GameServer.Log(picker.LogName + " threw " + item.Name, ServerLog.MessageType.ItemInteraction);
item.Drop();
item.body.ApplyLinearImpulse(throwVector * throwForce * item.body.Mass * 3.0f);
@@ -105,7 +105,7 @@ namespace Barotrauma.Items.Components
if (user != null)
{
GameServer.Log(user.Name + (IsActive ? " activated " : " deactivated ") + item.Name, ServerLog.MessageType.ItemInteraction);
GameServer.Log(user.LogName + (IsActive ? " activated " : " deactivated ") + item.Name, ServerLog.MessageType.ItemInteraction);
}
#if CLIENT
@@ -159,7 +159,7 @@ namespace Barotrauma.Items.Components
if (user != null)
{
GameServer.Log(user.Name + " started fabricating " + selectedItem.TargetItem.Name + " in " + item.Name, ServerLog.MessageType.ItemInteraction);
GameServer.Log(user.LogName + " started fabricating " + selectedItem.TargetItem.Name + " in " + item.Name, ServerLog.MessageType.ItemInteraction);
}
#if CLIENT
@@ -184,7 +184,7 @@ namespace Barotrauma.Items.Components
{
if (fabricatedItem != null && user != null)
{
GameServer.Log(user.Name + " cancelled the fabrication of " + fabricatedItem.TargetItem.Name + " in " + item.Name, ServerLog.MessageType.ItemInteraction);
GameServer.Log(user.LogName + " cancelled the fabrication of " + fabricatedItem.TargetItem.Name + " in " + item.Name, ServerLog.MessageType.ItemInteraction);
}
IsActive = false;
@@ -157,11 +157,11 @@ namespace Barotrauma.Items.Components
{
if (newFlowPercentage != FlowPercentage)
{
GameServer.Log(c.Character + " set the pumping speed of " + item.Name + " to " + (int)(newFlowPercentage) + " %", ServerLog.MessageType.ItemInteraction);
GameServer.Log(c.Character.LogName + " set the pumping speed of " + item.Name + " to " + (int)(newFlowPercentage) + " %", ServerLog.MessageType.ItemInteraction);
}
if (newIsActive != IsActive)
{
GameServer.Log(c.Character + (newIsActive ? " turned on " : " turned off ") + item.Name, ServerLog.MessageType.ItemInteraction);
GameServer.Log(c.Character.LogName + (newIsActive ? " turned on " : " turned off ") + item.Name, ServerLog.MessageType.ItemInteraction);
}
FlowPercentage = newFlowPercentage;
@@ -173,7 +173,7 @@ namespace Barotrauma.Items.Components
{
if (Timing.TotalTime >= (float)nextServerLogWriteTime)
{
GameServer.Log(lastUser + " adjusted reactor settings: " +
GameServer.Log(lastUser.LogName + " adjusted reactor settings: " +
"Temperature: " + (int)temperature +
", Fission rate: " + (int)fissionRate +
", Cooling rate: " + (int)coolingRate +
@@ -201,7 +201,7 @@ namespace Barotrauma.Items.Components
if (item.CanClientAccess(c))
{
RechargeSpeed = newRechargeSpeed;
GameServer.Log(c.Character + " set the recharge speed of "+item.Name+" to "+ (int)((rechargeSpeed / maxRechargeSpeed) * 100.0f) + " %", ServerLog.MessageType.ItemInteraction);
GameServer.Log(c.Character.LogName + " set the recharge speed of "+item.Name+" to "+ (int)((rechargeSpeed / maxRechargeSpeed) * 100.0f) + " %", ServerLog.MessageType.ItemInteraction);
}
item.CreateServerEvent(this);
@@ -215,7 +215,7 @@ namespace Barotrauma.Items.Components
if (existingWire.Locked)
{
//this should not be possible unless the client is running a modified version of the game
GameServer.Log(c.Character.Name + " attempted to disconnect a locked wire from " +
GameServer.Log(c.Character.LogName + " attempted to disconnect a locked wire from " +
Connections[i].Item.Name + " (" + Connections[i].Name + ")", ServerLog.MessageType.Error);
continue;
}
@@ -224,12 +224,12 @@ namespace Barotrauma.Items.Components
if (existingWire.Connections[0] == null && existingWire.Connections[1] == null)
{
GameServer.Log(c.Character.Name + " disconnected a wire from " +
GameServer.Log(c.Character.LogName + " disconnected a wire from " +
Connections[i].Item.Name + " (" + Connections[i].Name + ")", ServerLog.MessageType.ItemInteraction);
}
else if (existingWire.Connections[0] != null)
{
GameServer.Log(c.Character.Name + " disconnected a wire from " +
GameServer.Log(c.Character.LogName + " disconnected a wire from " +
Connections[i].Item.Name + " (" + Connections[i].Name + ") to " + existingWire.Connections[0].Item.Name + " (" + existingWire.Connections[0].Name + ")", ServerLog.MessageType.ItemInteraction);
//wires that are not in anyone's inventory (i.e. not currently being rewired)
@@ -244,7 +244,7 @@ namespace Barotrauma.Items.Components
}
else if (existingWire.Connections[1] != null)
{
GameServer.Log(c.Character.Name + " disconnected a wire from " +
GameServer.Log(c.Character.LogName + " disconnected a wire from " +
Connections[i].Item.Name + " (" + Connections[i].Name + ") to " + existingWire.Connections[1].Item.Name + " (" + existingWire.Connections[1].Name + ")", ServerLog.MessageType.ItemInteraction);
if (existingWire.Item.ParentInventory == null)
@@ -276,13 +276,13 @@ namespace Barotrauma.Items.Components
if (otherConnection == null)
{
GameServer.Log(c.Character.Name + " connected a wire to " +
GameServer.Log(c.Character.LogName + " connected a wire to " +
Connections[i].Item.Name + " (" + Connections[i].Name + ")",
ServerLog.MessageType.ItemInteraction);
}
else
{
GameServer.Log(c.Character.Name + " connected a wire from " +
GameServer.Log(c.Character.LogName + " connected a wire from " +
Connections[i].Item.Name + " (" + Connections[i].Name + ") to " +
(otherConnection == null ? "none" : otherConnection.Item.Name + " (" + (otherConnection.Name) + ")"),
ServerLog.MessageType.ItemInteraction);
@@ -308,18 +308,18 @@ namespace Barotrauma.Items.Components
{
if (connections[0] != null && connections[1] != null)
{
GameServer.Log(user.Name + " disconnected a wire from " +
GameServer.Log(user.LogName + " disconnected a wire from " +
connections[0].Item.Name + " (" + connections[0].Name + ") to "+
connections[1].Item.Name + " (" + connections[1].Name + ")", ServerLog.MessageType.ItemInteraction);
}
else if (connections[0] != null)
{
GameServer.Log(user.Name + " disconnected a wire from " +
GameServer.Log(user.LogName + " disconnected a wire from " +
connections[0].Item.Name + " (" + connections[0].Name + ")", ServerLog.MessageType.ItemInteraction);
}
else if (connections[1] != null)
{
GameServer.Log(user.Name + " disconnected a wire from " +
GameServer.Log(user.LogName + " disconnected a wire from " +
connections[1].Item.Name + " (" + connections[1].Name + ")", ServerLog.MessageType.ItemInteraction);
}
}
@@ -175,7 +175,7 @@ namespace Barotrauma.Items.Components
if (character != null)
{
string msg = character.Name + " launched " + item.Name + " (projectile: " + projectiles[0].Item.Name;
string msg = character.LogName + " launched " + item.Name + " (projectile: " + projectiles[0].Item.Name;
if (projectiles[0].Item.ContainedItems == null || projectiles[0].Item.ContainedItems.All(i => i == null))
{
msg += ")";
@@ -144,7 +144,7 @@ namespace Barotrauma
{
if (itemName == null) return null;
return Items.FirstOrDefault(i => i != null && (i.Name == itemName || i.HasTag(itemName)));
return Items.FirstOrDefault(i => i != null && (i.Prefab.NameMatches(itemName) || i.HasTag(itemName)));
}
public virtual void RemoveItem(Item item)
@@ -212,11 +212,11 @@ namespace Barotrauma
{
if (Owner == c.Character)
{
GameServer.Log(c.Character + " picked up " + item.Name, ServerLog.MessageType.Inventory);
GameServer.Log(c.Character.LogName+ " picked up " + item.Name, ServerLog.MessageType.Inventory);
}
else
{
GameServer.Log(c.Character + " placed " + item.Name + " in " + Owner, ServerLog.MessageType.Inventory);
GameServer.Log(c.Character.LogName + " placed " + item.Name + " in " + Owner, ServerLog.MessageType.Inventory);
}
}
}
@@ -227,11 +227,11 @@ namespace Barotrauma
{
if (Owner == c.Character)
{
GameServer.Log(c.Character + " dropped " + item.Name, ServerLog.MessageType.Inventory);
GameServer.Log(c.Character.LogName + " dropped " + item.Name, ServerLog.MessageType.Inventory);
}
else
{
GameServer.Log(c.Character + " removed " + item.Name + " from " + Owner, ServerLog.MessageType.Inventory);
GameServer.Log(c.Character.LogName + " removed " + item.Name + " from " + Owner, ServerLog.MessageType.Inventory);
}
}
}
@@ -119,9 +119,12 @@ namespace Barotrauma
get { return prefab.Name; }
}
private string description;
[Editable, Serialize("", true)]
public string Description
{
get { return prefab.Description; }
get { return description == null ? prefab.Description : description; }
set { description = value; }
}
public float ImpactTolerance
@@ -1359,12 +1362,12 @@ namespace Barotrauma
if (ContainedItems == null || ContainedItems.All(i => i == null))
{
GameServer.Log(c.Character.Name + " used item " + Name, ServerLog.MessageType.ItemInteraction);
GameServer.Log(c.Character.LogName + " used item " + Name, ServerLog.MessageType.ItemInteraction);
}
else
{
GameServer.Log(
c.Character.Name + " used item " + Name + " (contained items: " + string.Join(", ", Array.FindAll(ContainedItems, i => i != null).Select(i => i.Name)) + ")",
c.Character.LogName + " used item " + Name + " (contained items: " + string.Join(", ", Array.FindAll(ContainedItems, i => i != null).Select(i => i.Name)) + ")",
ServerLog.MessageType.ItemInteraction);
}
@@ -1458,6 +1461,7 @@ namespace Barotrauma
if (GameMain.Server == null) return;
msg.Write(Prefab.Name);
msg.Write(Description);
msg.Write(ID);
if (ParentInventory == null || ParentInventory.Owner == null)
@@ -1476,7 +1480,8 @@ namespace Barotrauma
msg.Write(index < 0 ? (byte)255 : (byte)index);
}
if (Name == "ID Card") msg.Write(Tags);
//TODO: See if tags are different from their prefab before sending 'em
msg.Write(Tags);
}
public static Item ReadSpawnData(NetBuffer msg, bool spawn = true)
@@ -1484,6 +1489,7 @@ namespace Barotrauma
if (GameMain.Server != null) return null;
string itemName = msg.ReadString();
string itemDesc = msg.ReadString();
ushort itemId = msg.ReadUInt16();
ushort inventoryId = msg.ReadUInt16();
@@ -1507,11 +1513,7 @@ namespace Barotrauma
}
}
string tags = "";
if (itemName == "ID Card")
{
tags = msg.ReadString();
}
string tags = msg.ReadString();
if (!spawn) return null;
@@ -1541,6 +1543,7 @@ namespace Barotrauma
var item = new Item(itemPrefab, pos, sub);
item.Description = itemDesc;
item.ID = itemId;
if (sub != null)
{
@@ -506,15 +506,15 @@ namespace Barotrauma
float impact = Vector2.Dot(f2.Body.LinearVelocity, -normal)*f2.Body.Mass*0.1f;
if (impact < 10.0f) return true;
#if CLIENT
SoundPlayer.PlayDamageSound(DamageSoundType.StructureBlunt, impact,
new Vector2(
sections[section].rect.X + sections[section].rect.Width / 2,
sections[section].rect.Y - sections[section].rect.Height / 2));
sections[section].rect.X + sections[section].rect.Width / 2,
sections[section].rect.Y - sections[section].rect.Height / 2), tags: Tags);
#endif
if (impact < 10.0f) return true;
AddDamage(section, impact);
}
}
@@ -566,7 +566,7 @@ namespace Barotrauma
#if CLIENT
float particleAmount = Math.Min(Health - section.damage, damage) * Rand.Range(0.01f, 1.0f);
particleAmount = Math.Min(particleAmount + Rand.Range(-5,1), 100);
particleAmount = Math.Min(particleAmount + Rand.Range(-5,1), 20);
for (int i = 0; i < particleAmount; i++)
{
Vector2 particlePos = new Vector2(
@@ -661,10 +661,10 @@ namespace Barotrauma
#if CLIENT
GameMain.ParticleManager.CreateParticle("dustcloud", SectionPosition(i), 0.0f, 0.0f);
if (playSound && !SectionBodyDisabled(i))
if (playSound)// && !SectionBodyDisabled(i))
{
DamageSoundType damageSoundType = (attack.DamageType == DamageType.Blunt) ? DamageSoundType.StructureBlunt : DamageSoundType.StructureSlash;
SoundPlayer.PlayDamageSound(damageSoundType, damageAmount, worldPosition);
SoundPlayer.PlayDamageSound(damageSoundType, damageAmount, worldPosition, tags: Tags);
}
#endif
@@ -678,14 +678,13 @@ namespace Barotrauma
if (!MathUtils.IsValid(damage)) return;
float damageDiff = damage - sections[sectionIndex].damage;
if (GameMain.Server != null && damage != sections[sectionIndex].damage)
{
GameMain.Server.CreateEntityEvent(this);
}
AdjustKarma(attacker, damageDiff);
if (damage < prefab.Health*0.5f)
{
if (sections[sectionIndex].gap != null)
@@ -717,10 +716,14 @@ namespace Barotrauma
sections[sectionIndex].gap.Open = (damage / prefab.Health - 0.5f) * 2.0f;
}
float damageDiff = damage - sections[sectionIndex].damage;
bool hadHole = SectionBodyDisabled(sectionIndex);
sections[sectionIndex].damage = MathHelper.Clamp(damage, 0.0f, prefab.Health);
if (sections[sectionIndex].damage < prefab.Health) //otherwise it's possible to infinitely gain karma by welding fixed things
AdjustKarma(attacker, damageDiff);
bool hasHole = SectionBodyDisabled(sectionIndex);
if (hadHole == hasHole) return;
@@ -373,118 +373,53 @@ namespace Barotrauma
Limb limb = f2.Body.UserData as Limb;
if (limb != null)
{
bool collision = HandleLimbCollision(contact, limb);
if (collision && limb.Mass > 100.0f)
{
Vector2 normal = Vector2.Normalize(Body.SimPosition - limb.SimPosition);
float impact = Math.Min(Vector2.Dot(Velocity - limb.LinearVelocity, -normal), 50.0f) / 5.0f * Math.Min(limb.Mass / 200.0f, 1);
ApplyImpact(impact, -normal, contact);
foreach (Submarine dockedSub in submarine.DockedTo)
{
dockedSub.SubBody.ApplyImpact(impact, -normal, contact);
}
}
bool collision = CheckLimbCollision(contact, limb);
if (collision) HandleLimbCollision(contact, limb);
return collision;
}
VoronoiCell cell = f2.Body.UserData as VoronoiCell;
if (cell != null)
{
var collisionNormal = Vector2.Normalize(ConvertUnits.ToDisplayUnits(Body.SimPosition) - cell.Center);
float wallImpact = Vector2.Dot(Velocity, -collisionNormal);
ApplyImpact(wallImpact, -collisionNormal, contact);
foreach (Submarine dockedSub in submarine.DockedTo)
{
dockedSub.SubBody.ApplyImpact(wallImpact, -collisionNormal, contact);
}
Vector2 n;
FixedArray2<Vector2> particlePos;
contact.GetWorldManifold(out n, out particlePos);
#if CLIENT
int particleAmount = (int)(wallImpact * 10.0f);
for (int i = 0; i < particleAmount; i++)
{
GameMain.ParticleManager.CreateParticle("iceshards",
ConvertUnits.ToDisplayUnits(particlePos[0]) + Rand.Vector(Rand.Range(1.0f, 50.0f)),
Rand.Vector(Rand.Range(50.0f, 500.0f)) + Velocity);
}
#endif
HandleLevelCollision(contact, cell);
return true;
}
Submarine otherSub = f2.Body.UserData as Submarine;
if (otherSub != null)
{
Debug.Assert(otherSub != submarine);
Vector2 normal;
FixedArray2<Vector2> points;
contact.GetWorldManifold(out normal, out points);
if (contact.FixtureA.Body == otherSub.SubBody.Body.FarseerBody)
{
normal = -normal;
}
float thisMass = Body.Mass + submarine.DockedTo.Sum(s => s.PhysicsBody.Mass);
float otherMass = otherSub.PhysicsBody.Mass + otherSub.DockedTo.Sum(s => s.PhysicsBody.Mass);
float massRatio = otherMass / (thisMass + otherMass);
float impact = (Vector2.Dot(Velocity - otherSub.Velocity, normal) / 2.0f) * massRatio;
ApplyImpact(impact, normal, contact);
foreach (Submarine dockedSub in submarine.DockedTo)
{
dockedSub.SubBody.ApplyImpact(impact, normal, contact);
}
HandleSubCollision(contact, otherSub);
return true;
}
return true;
}
private bool HandleLimbCollision(Contact contact, Limb limb)
private bool CheckLimbCollision(Contact contact, Limb limb)
{
if (limb.character.Submarine != null) return false;
Vector2 normal2;
Vector2 contactNormal;
FixedArray2<Vector2> points;
contact.GetWorldManifold(out normal2, out points);
contact.GetWorldManifold(out contactNormal, out points);
Vector2 normalizedVel = limb.character.AnimController.Collider.LinearVelocity == Vector2.Zero ?
Vector2.Zero : Vector2.Normalize(limb.character.AnimController.Collider.LinearVelocity);
Vector2 targetPos = ConvertUnits.ToDisplayUnits(points[0] - normal2);
Vector2 targetPos = ConvertUnits.ToDisplayUnits(points[0] - contactNormal);
Hull newHull = Hull.FindHull(targetPos, null);
if (newHull == null)
{
targetPos = ConvertUnits.ToDisplayUnits(points[0] + normalizedVel);
newHull = Hull.FindHull(targetPos, null);
if (newHull == null) return true;
}
var gaps = newHull.ConnectedGaps;
targetPos = limb.character.WorldPosition;
Gap adjacentGap = Gap.FindAdjacent(gaps, targetPos, 200.0f);
if (adjacentGap==null) return true;
if (adjacentGap == null) return true;
var ragdoll = limb.character.AnimController;
ragdoll.FindHull(newHull.WorldPosition, true);
@@ -492,13 +427,190 @@ namespace Barotrauma
return false;
}
private void HandleLimbCollision(Contact contact, Limb limb)
{
if (limb.Mass > 100.0f)
{
Vector2 normal = Vector2.Normalize(Body.SimPosition - limb.SimPosition);
float impact = Math.Min(Vector2.Dot(Velocity - limb.LinearVelocity, -normal), 50.0f) / 5.0f * Math.Min(limb.Mass / 200.0f, 1);
ApplyImpact(impact, -normal, contact);
foreach (Submarine dockedSub in submarine.DockedTo)
{
dockedSub.SubBody.ApplyImpact(impact, -normal, contact);
}
}
//find all contacts between the limb and level walls
List<Contact> levelContacts = new List<Contact>();
ContactEdge contactEdge = limb.body.FarseerBody.ContactList;
while (contactEdge.Next != null)
{
if (contactEdge.Contact.Enabled &&
contactEdge.Other.UserData is VoronoiCell &&
contactEdge.Contact.IsTouching)
{
levelContacts.Add(contactEdge.Contact);
}
contactEdge = contactEdge.Next;
}
if (levelContacts.Count == 0) return;
//if the limb is in contact with the level, apply an artifical impact to prevent the sub from bouncing on top of it
//not a very realistic way to handle the collisions (makes it seem as if the characters were made of reinforced concrete),
//but more realistic than bouncing and prevents using characters as "bumpers" that prevent all collision damage
//TODO: apply impact damage and/or gib the character that got crushed between the sub and the level?
Vector2 avgContactNormal = Vector2.Zero;
foreach (Contact levelContact in levelContacts)
{
Vector2 contactNormal;
FixedArray2<Vector2> temp;
levelContact.GetWorldManifold(out contactNormal, out temp);
//if the contact normal is pointing from the limb towards the level cell it's touching, flip the normal
VoronoiCell cell = levelContact.FixtureB.Body.UserData is VoronoiCell ?
((VoronoiCell)levelContact.FixtureB.Body.UserData) : ((VoronoiCell)levelContact.FixtureA.Body.UserData);
var cellDiff = ConvertUnits.ToDisplayUnits(limb.body.SimPosition) - cell.Center;
if (Vector2.Dot(contactNormal, cellDiff) < 0)
{
contactNormal = -contactNormal;
}
avgContactNormal += contactNormal;
//apply impacts at the positions where this sub is touching the limb
ApplyImpact((Vector2.Dot(-Velocity, contactNormal) / 2.0f) / levelContacts.Count, contactNormal, levelContact);
}
avgContactNormal /= levelContacts.Count;
float contactDot = Vector2.Dot(Body.LinearVelocity, -avgContactNormal);
if (contactDot > 0.0f)
{
Body.LinearVelocity -= Vector2.Normalize(Body.LinearVelocity) * contactDot;
}
}
private void HandleLevelCollision(Contact contact, VoronoiCell cell)
{
var collisionNormal = Vector2.Normalize(ConvertUnits.ToDisplayUnits(Body.SimPosition) - cell.Center);
float wallImpact = Vector2.Dot(Velocity, -collisionNormal);
ApplyImpact(wallImpact, -collisionNormal, contact);
foreach (Submarine dockedSub in submarine.DockedTo)
{
dockedSub.SubBody.ApplyImpact(wallImpact, -collisionNormal, contact);
}
Vector2 n;
FixedArray2<Vector2> particlePos;
contact.GetWorldManifold(out n, out particlePos);
#if CLIENT
int particleAmount = (int)Math.Min(wallImpact * 10.0f, 50);
for (int i = 0; i < particleAmount; i++)
{
GameMain.ParticleManager.CreateParticle("iceshards",
ConvertUnits.ToDisplayUnits(particlePos[0]) + Rand.Vector(Rand.Range(1.0f, 50.0f)),
Rand.Vector(Rand.Range(50.0f, 500.0f)) + Velocity);
}
#endif
}
private void HandleSubCollision(Contact contact, Submarine otherSub)
{
Debug.Assert(otherSub != submarine);
Vector2 normal;
FixedArray2<Vector2> points;
contact.GetWorldManifold(out normal, out points);
if (contact.FixtureA.Body == otherSub.SubBody.Body.FarseerBody)
{
normal = -normal;
}
float thisMass = Body.Mass + submarine.DockedTo.Sum(s => s.PhysicsBody.Mass);
float otherMass = otherSub.PhysicsBody.Mass + otherSub.DockedTo.Sum(s => s.PhysicsBody.Mass);
float massRatio = otherMass / (thisMass + otherMass);
float impact = (Vector2.Dot(Velocity - otherSub.Velocity, normal) / 2.0f) * massRatio;
//apply impact to this sub (the other sub takes care of this in its own collision callback)
ApplyImpact(impact, normal, contact);
foreach (Submarine dockedSub in submarine.DockedTo)
{
dockedSub.SubBody.ApplyImpact(impact, normal, contact);
}
//find all contacts between this sub and level walls
List<Contact> levelContacts = new List<Contact>();
ContactEdge contactEdge = Body.FarseerBody.ContactList;
while (contactEdge.Next != null)
{
if (contactEdge.Contact.Enabled &&
contactEdge.Other.UserData is VoronoiCell &&
contactEdge.Contact.IsTouching)
{
levelContacts.Add(contactEdge.Contact);
}
contactEdge = contactEdge.Next;
}
if (levelContacts.Count == 0) return;
//if this sub is in contact with the level, apply artifical impacts
//to both subs to prevent the other sub from bouncing on top of this one
//and to fake the other sub "crushing" this one against a wall
Vector2 avgContactNormal = Vector2.Zero;
foreach (Contact levelContact in levelContacts)
{
Vector2 contactNormal;
FixedArray2<Vector2> temp;
levelContact.GetWorldManifold(out contactNormal, out temp);
//if the contact normal is pointing from the sub towards the level cell we collided with, flip the normal
VoronoiCell cell = levelContact.FixtureB.Body.UserData is VoronoiCell ?
((VoronoiCell)levelContact.FixtureB.Body.UserData) : ((VoronoiCell)levelContact.FixtureA.Body.UserData);
var cellDiff = ConvertUnits.ToDisplayUnits(Body.SimPosition) - cell.Center;
if (Vector2.Dot(contactNormal, cellDiff) < 0)
{
contactNormal = -contactNormal;
}
avgContactNormal += contactNormal;
//apply impacts at the positions where this sub is touching the level
ApplyImpact((Vector2.Dot(Velocity - otherSub.Velocity, contactNormal) / 2.0f) * massRatio / levelContacts.Count, contactNormal, levelContact);
}
avgContactNormal /= levelContacts.Count;
//apply an impact to the other sub
float contactDot = Vector2.Dot(otherSub.PhysicsBody.LinearVelocity, -avgContactNormal);
if (contactDot > 0.0f)
{
otherSub.PhysicsBody.LinearVelocity -= Vector2.Normalize(otherSub.PhysicsBody.LinearVelocity) * contactDot;
impact = Vector2.Dot(otherSub.Velocity, normal);
otherSub.SubBody.ApplyImpact(impact, normal, contact);
foreach (Submarine dockedSub in otherSub.DockedTo)
{
dockedSub.SubBody.ApplyImpact(impact, normal, contact);
}
}
}
private void ApplyImpact(float impact, Vector2 direction, Contact contact)
{
if (impact < 3.0f) return;
Vector2 tempNormal;
FarseerPhysics.Common.FixedArray2<Vector2> worldPoints;
FixedArray2<Vector2> worldPoints;
contact.GetWorldManifold(out tempNormal, out worldPoints);
Vector2 lastContactPoint = worldPoints[0];
@@ -537,6 +649,7 @@ namespace Barotrauma
var damagedStructures = Explosion.RangedStructureDamage(ConvertUnits.ToDisplayUnits(lastContactPoint), impact * 50.0f, impact * DamageMultiplier);
#if CLIENT
//play a damage sound for the structure that took the most damage
float maxDamage = 0.0f;
Structure maxDamageStructure = null;
@@ -549,7 +662,6 @@ namespace Barotrauma
}
}
#if CLIENT
if (maxDamageStructure != null)
{
SoundPlayer.PlayDamageSound(
@@ -21,6 +21,7 @@ namespace Barotrauma
protected SpawnType spawnType;
//characters spawning at the waypoint will be given an ID card with these tags
private string idCardDesc;
private string[] idCardTags;
//only characters with this job will be spawned at the waypoint
@@ -57,6 +58,11 @@ namespace Barotrauma
}
}
public string IdCardDesc
{
get { return idCardDesc; }
private set { idCardDesc = value; }
}
public string[] IdCardTags
{
get { return idCardTags; }
@@ -113,6 +119,7 @@ namespace Barotrauma
public override MapEntity Clone()
{
var clone = new WayPoint(rect, Submarine);
clone.idCardDesc = idCardDesc;
clone.idCardTags = idCardTags;
clone.spawnType = spawnType;
clone.assignedJob = assignedJob;
@@ -570,6 +577,11 @@ namespace Barotrauma
Enum.TryParse<SpawnType>(element.GetAttributeString("spawn", "Path"), out w.spawnType);
string idCardDescString = element.GetAttributeString("idcarddesc", "");
if (!string.IsNullOrWhiteSpace(idCardDescString))
{
w.IdCardDesc = idCardDescString;
}
string idCardTagString = element.GetAttributeString("idcardtags", "");
if (!string.IsNullOrWhiteSpace(idCardTagString))
{
@@ -604,6 +616,7 @@ namespace Barotrauma
new XAttribute("y", (int)(rect.Y - Submarine.HiddenSubPosition.Y)),
new XAttribute("spawn", spawnType));
if (!string.IsNullOrWhiteSpace(idCardDesc)) element.Add(new XAttribute("idcarddesc", idCardDesc));
if (idCardTags.Length > 0)
{
element.Add(new XAttribute("idcardtags", string.Join(",", idCardTags)));
@@ -7,7 +7,7 @@ namespace Barotrauma.Networking
{
enum ChatMessageType
{
Default, Error, Dead, Server, Radio, Private, MessageBox
Default, Error, Dead, Server, Radio, Private, Console, MessageBox
}
partial class ChatMessage
@@ -25,7 +25,8 @@ namespace Barotrauma.Networking
new Color(63, 72, 204), //dead
new Color(157, 225, 160), //server
new Color(238, 208, 0), //radio
new Color(64, 240, 89) //private
new Color(64, 240, 89), //private
new Color(255, 255, 255) //console
};
public readonly string Text;
@@ -105,18 +106,18 @@ namespace Barotrauma.Networking
return ApplyDistanceEffect(listener, Sender, Text, SpeakRange);
}
public static string ApplyDistanceEffect(Entity listener, Entity Sender, string text, float range)
public static string ApplyDistanceEffect(Entity listener, Entity Sender, string text, float range, float obstructionmult = 2.0f)
{
if (listener.WorldPosition == Sender.WorldPosition) return text;
float dist = Vector2.Distance(listener.WorldPosition, Sender.WorldPosition);
if (dist > range) return "";
if (Submarine.CheckVisibility(listener.SimPosition, Sender.SimPosition) != null) dist *= 2.0f;
if (Submarine.CheckVisibility(listener.SimPosition, Sender.SimPosition) != null) dist = (dist + 100f) * obstructionmult;
if (dist > range) return "";
float garbleAmount = dist / range;
if (garbleAmount < 0.5f) return text;
if (garbleAmount < 0.3f) return text;
int startIndex = Math.Max(text.IndexOf(':') + 1, 1);
@@ -1,29 +1,10 @@
using Lidgren.Network;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
namespace Barotrauma.Networking
{
[Flags]
enum ClientPermissions
{
None = 0,
[Description("End round")]
EndRound = 1,
[Description("Kick")]
Kick = 2,
[Description("Ban")]
Ban = 4,
[Description("Select submarine")]
SelectSub = 8,
[Description("Select game mode")]
SelectMode = 16,
[Description("Manage campaign")]
ManageCampaign = 32
}
class Client
{
public string Name;
@@ -96,6 +77,11 @@ namespace Barotrauma.Networking
public float DeleteDisconnectedTimer;
public ClientPermissions Permissions = ClientPermissions.None;
public List<DebugConsole.Command> PermittedConsoleCommands
{
get;
private set;
}
public bool SpectateOnly;
@@ -130,6 +116,7 @@ namespace Barotrauma.Networking
this.Name = name;
this.ID = ID;
PermittedConsoleCommands = new List<DebugConsole.Command>();
kickVoters = new List<Client>();
votes = new object[Enum.GetNames(typeof(VoteType)).Length];
@@ -171,9 +158,10 @@ namespace Barotrauma.Networking
return rName;
}
public void SetPermissions(ClientPermissions permissions)
public void SetPermissions(ClientPermissions permissions, List<DebugConsole.Command> permittedConsoleCommands)
{
this.Permissions = permissions;
this.PermittedConsoleCommands = new List<DebugConsole.Command>(permittedConsoleCommands);
}
public void GivePermission(ClientPermissions permission)
@@ -0,0 +1,82 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Xml.Linq;
namespace Barotrauma.Networking
{
[Flags]
enum ClientPermissions
{
None = 0,
[Description("End round")]
EndRound = 1,
[Description("Kick")]
Kick = 2,
[Description("Ban")]
Ban = 4,
[Description("Select submarine")]
SelectSub = 8,
[Description("Select game mode")]
SelectMode = 16,
[Description("Manage campaign")]
ManageCampaign = 32,
[Description("Console commands")]
ConsoleCommands = 64
}
class PermissionPreset
{
public static List<PermissionPreset> List = new List<PermissionPreset>();
public readonly string Name;
public readonly string Description;
public readonly ClientPermissions Permissions;
public readonly List<DebugConsole.Command> PermittedCommands;
public PermissionPreset(XElement element)
{
Name = element.GetAttributeString("name", "");
Description = element.GetAttributeString("description", "");
string permissionsStr = element.GetAttributeString("permissions", "");
if (!Enum.TryParse(permissionsStr, out Permissions))
{
DebugConsole.ThrowError("Error in permission preset \"" + Name + "\" - " + permissionsStr + " is not a valid permission!");
}
PermittedCommands = new List<DebugConsole.Command>();
if (Permissions.HasFlag(ClientPermissions.ConsoleCommands))
{
foreach (XElement subElement in element.Elements())
{
if (subElement.Name.ToString().ToLowerInvariant() != "command") continue;
string commandName = subElement.GetAttributeString("name", "");
DebugConsole.Command command = DebugConsole.FindCommand(commandName);
if (command == null)
{
DebugConsole.ThrowError("Error in permission preset \"" + Name + "\" - " + commandName + "\" is not a valid console command.");
continue;
}
PermittedCommands.Add(command);
}
}
}
public static void LoadAll(string file)
{
if (!File.Exists(file)) return;
XDocument doc = XMLExtensions.TryLoadXml(file);
if (doc == null || doc.Root == null) return;
foreach (XElement element in doc.Root.Elements())
{
List.Add(new PermissionPreset(element));
}
}
}
}
@@ -125,8 +125,9 @@ namespace Barotrauma.Networking
banList = new BanList();
LoadSettings();
PermissionPreset.LoadAll(PermissionPresetFile);
LoadClientPermissions();
CoroutineManager.StartCoroutine(StartServer(isPublic));
}
@@ -795,6 +796,11 @@ namespace Barotrauma.Networking
campaign.ServerRead(inc, sender);
}
break;
case ClientPermissions.ConsoleCommands:
string consoleCommand = inc.ReadString();
Vector2 clientCursorPos = new Vector2(inc.ReadSingle(), inc.ReadSingle());
DebugConsole.ExecuteClientCommand(sender, clientCursorPos, consoleCommand);
break;
}
inc.ReadPadBits();
@@ -853,7 +859,7 @@ namespace Barotrauma.Networking
outmsg.Write(GameStarted);
outmsg.Write(AllowSpectating);
outmsg.Write((byte)c.Permissions);
WritePermissions(outmsg, c);
}
private void ClientWriteIngame(Client c)
@@ -1636,6 +1642,18 @@ namespace Barotrauma.Networking
}
}
public void SendChatMessage(string txt, Client recipient)
{
ChatMessage msg = ChatMessage.Create("", txt, ChatMessageType.Server, null);
SendChatMessage(msg, recipient);
}
public void SendConsoleMessage(string txt, Client recipient)
{
ChatMessage msg = ChatMessage.Create("", txt, ChatMessageType.Console, null);
SendChatMessage(msg, recipient);
}
public void SendChatMessage(ChatMessage msg, Client recipient)
{
msg.NetStateID = recipient.ChatMsgQueue.Count > 0 ?
@@ -1848,7 +1866,7 @@ namespace Barotrauma.Networking
case ChatMessageType.Default:
if (!receiver.IsDead)
{
return ChatMessage.ApplyDistanceEffect(receiver, sender, message, ChatMessage.SpeakRange);
return ChatMessage.ApplyDistanceEffect(receiver, sender, message, ChatMessage.SpeakRange, 3.0f);
}
break;
case ChatMessageType.Radio:
@@ -1936,16 +1954,34 @@ namespace Barotrauma.Networking
clientPermissions.Add(new SavedClientPermission(
client.Name,
client.Connection.RemoteEndPoint.Address.ToString(),
client.Permissions));
client.Permissions,
client.PermittedConsoleCommands));
}
var msg = server.CreateMessage();
msg.Write((byte)ServerPacketHeader.PERMISSIONS);
msg.Write((byte)client.Permissions);
WritePermissions(msg, client);
server.SendMessage(msg, client.Connection, NetDeliveryMethod.ReliableUnordered);
SaveClientPermissions();
}
private void WritePermissions(NetBuffer msg, Client client)
{
msg.Write((byte)client.Permissions);
if (client.Permissions.HasFlag(ClientPermissions.ConsoleCommands))
{
msg.Write((UInt16)client.PermittedConsoleCommands.Sum(c => c.names.Length));
foreach (DebugConsole.Command command in client.PermittedConsoleCommands)
{
foreach (string commandName in command.names)
{
msg.Write(commandName);
}
}
}
}
public void SetClientCharacter(Client client, Character newCharacter)
{
@@ -218,11 +218,11 @@ namespace Barotrauma.Networking
var savedPermissions = clientPermissions.Find(cp => cp.IP == newClient.Connection.RemoteEndPoint.Address.ToString());
if (savedPermissions != null)
{
newClient.SetPermissions(savedPermissions.Permissions);
newClient.SetPermissions(savedPermissions.Permissions, savedPermissions.PermittedCommands);
}
else
{
newClient.SetPermissions(ClientPermissions.None);
newClient.SetPermissions(ClientPermissions.None, new List<DebugConsole.Command>());
}
}
@@ -25,20 +25,23 @@ namespace Barotrauma.Networking
{
public readonly string IP;
public readonly string Name;
public List<DebugConsole.Command> PermittedCommands;
public ClientPermissions Permissions;
public SavedClientPermission(string name, string ip, ClientPermissions permissions)
public SavedClientPermission(string name, string ip, ClientPermissions permissions, List<DebugConsole.Command> permittedCommands)
{
this.Name = name;
this.IP = ip;
this.Permissions = permissions;
this.PermittedCommands = permittedCommands;
}
}
public const string SettingsFile = "serversettings.xml";
public static readonly string ClientPermissionsFile = "Data" + Path.DirectorySeparatorChar + "clientpermissions.txt";
public static readonly string PermissionPresetFile = "Data" + Path.DirectorySeparatorChar + "permissionpresets.xml";
public static readonly string ClientPermissionsFile = "Data" + Path.DirectorySeparatorChar + "clientpermissions.xml";
public Dictionary<string, SerializableProperty> SerializableProperties
{
@@ -130,6 +133,13 @@ namespace Barotrauma.Networking
private set;
}
[Serialize(true, true)]
public bool AllowRagdollButton
{
get;
private set;
}
[Serialize(true, true)]
public bool AllowFileTransfers
{
@@ -210,6 +220,20 @@ namespace Barotrauma.Networking
private set;
}
[Serialize(true, true)]
public bool TraitorUseRatio
{
get;
private set;
}
[Serialize(0.2f, true)]
public float TraitorRatio
{
get;
private set;
}
[Serialize(false,true)]
public bool KarmaEnabled
{
@@ -323,12 +347,67 @@ namespace Barotrauma.Networking
public void LoadClientPermissions()
{
if (!File.Exists(ClientPermissionsFile)) return;
clientPermissions.Clear();
if (File.Exists("Data/clientpermissions.txt") && !File.Exists(ClientPermissionsFile))
{
LoadClientPermissionsOld("Data/clientpermissions.txt");
return;
}
XDocument doc = XMLExtensions.TryLoadXml(ClientPermissionsFile);
foreach (XElement clientElement in doc.Root.Elements())
{
string clientName = clientElement.GetAttributeString("name", "");
string clientIP = clientElement.GetAttributeString("ip", "");
if (string.IsNullOrWhiteSpace(clientName) || string.IsNullOrWhiteSpace(clientIP))
{
DebugConsole.ThrowError("Error in " + ClientPermissionsFile + " - all clients must have a name and an IP address.");
continue;
}
string permissionsStr = clientElement.GetAttributeString("permissions", "");
ClientPermissions permissions;
if (!Enum.TryParse(permissionsStr, out permissions))
{
DebugConsole.ThrowError("Error in " + ClientPermissionsFile + " - \"" + permissionsStr + "\" is not a valid client permission.");
continue;
}
List<DebugConsole.Command> permittedCommands = new List<DebugConsole.Command>();
if (permissions.HasFlag(ClientPermissions.ConsoleCommands))
{
foreach (XElement commandElement in clientElement.Elements())
{
if (commandElement.Name.ToString().ToLowerInvariant() != "command") continue;
string commandName = commandElement.GetAttributeString("name", "");
DebugConsole.Command command = DebugConsole.FindCommand(commandName);
if (command == null)
{
DebugConsole.ThrowError("Error in " + ClientPermissionsFile + " - \"" + commandName + "\" is not a valid console command.");
continue;
}
permittedCommands.Add(command);
}
}
clientPermissions.Add(new SavedClientPermission(clientName, clientIP, permissions, permittedCommands));
}
}
/// <summary>
/// Method for loading old .txt client permission files to provide backwards compatibility
/// </summary>
private void LoadClientPermissionsOld(string file)
{
if (!File.Exists(file)) return;
string[] lines;
try
{
lines = File.ReadAllLines(ClientPermissionsFile);
lines = File.ReadAllLines(file);
}
catch (Exception e)
{
@@ -337,36 +416,63 @@ namespace Barotrauma.Networking
}
clientPermissions.Clear();
foreach (string line in lines)
{
string[] separatedLine = line.Split('|');
if (separatedLine.Length < 3) continue;
string name = String.Join("|", separatedLine.Take(separatedLine.Length - 2));
string name = string.Join("|", separatedLine.Take(separatedLine.Length - 2));
string ip = separatedLine[separatedLine.Length - 2];
ClientPermissions permissions = ClientPermissions.None;
if (Enum.TryParse<ClientPermissions>(separatedLine.Last(), out permissions))
if (Enum.TryParse(separatedLine.Last(), out permissions))
{
clientPermissions.Add(new SavedClientPermission(name, ip, permissions));
clientPermissions.Add(new SavedClientPermission(name, ip, permissions, new List<DebugConsole.Command>()));
}
}
}
public void SaveClientPermissions()
{
GameServer.Log("Saving client permissions", ServerLog.MessageType.ServerMessage);
//delete old client permission file
if (File.Exists("Data/clientpermissions.txt"))
{
File.Delete("Data/clientpermissions.txt");
}
List<string> lines = new List<string>();
Log("Saving client permissions", ServerLog.MessageType.ServerMessage);
XDocument doc = new XDocument(new XElement("ClientPermissions"));
foreach (SavedClientPermission clientPermission in clientPermissions)
{
lines.Add(clientPermission.Name + "|" + clientPermission.IP+"|"+clientPermission.Permissions.ToString());
XElement clientElement = new XElement("Client",
new XAttribute("name", clientPermission.Name),
new XAttribute("ip", clientPermission.IP),
new XAttribute("permissions", clientPermission.Permissions.ToString()));
if (clientPermission.Permissions.HasFlag(ClientPermissions.ConsoleCommands))
{
foreach (DebugConsole.Command command in clientPermission.PermittedCommands)
{
clientElement.Add(new XElement("command", new XAttribute("name", command.names[0])));
}
}
doc.Root.Add(clientElement);
}
try
{
File.WriteAllLines(ClientPermissionsFile, lines);
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
settings.NewLineOnAttributes = true;
using (var writer = XmlWriter.Create(ClientPermissionsFile, settings))
{
doc.Save(writer);
}
}
catch (Exception e)
{
@@ -533,7 +533,9 @@ namespace Barotrauma.Networking
foreach (string s in shuttleSpawnPoints[i].IdCardTags)
{
item.AddTag(s);
}
}
if (!string.IsNullOrWhiteSpace(shuttleSpawnPoints[i].IdCardDesc))
item.Description = shuttleSpawnPoints[i].IdCardDesc;
}
#if CLIENT
GameMain.GameSession.CrewManager.AddCharacter(character);
@@ -28,18 +28,20 @@ namespace Barotrauma.Networking
Attack,
Spawning,
ServerMessage,
ConsoleUsage,
Error
}
private readonly Color[] messageColor =
{
Color.LightBlue,
new Color(255, 142, 0),
new Color(238, 208, 0),
new Color(204, 74, 78),
new Color(163, 73, 164),
new Color(157, 225, 160),
Color.Red
Color.LightBlue, //Chat
new Color(255, 142, 0), //ItemInteraction
new Color(238, 208, 0), //Inventory
new Color(204, 74, 78), //Attack
new Color(163, 73, 164), //Spawning
new Color(157, 225, 160), //ServerMessage
new Color(0, 162, 232), //ConsoleUsage
Color.Red //Error
};
private readonly string[] messageTypeName =
@@ -50,6 +52,7 @@ namespace Barotrauma.Networking
"Attack & death",
"Spawning",
"Server message",
"Console usage",
"Error"
};