Reorganized project to start work on dedicated server

This commit is contained in:
juanjp600
2017-06-11 03:48:08 -03:00
parent 9b0d7c1020
commit 5636d1cdf9
702 changed files with 453 additions and 247 deletions
@@ -0,0 +1,318 @@
using System;
using System.Xml.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Barotrauma.Networking;
using Lidgren.Network;
namespace Barotrauma.Items.Components
{
class PowerContainer : Powered, IDrawableComponent, IServerSerializable, IClientSerializable
{
//[power/min]
private float capacity;
private float charge;
private float rechargeVoltage, outputVoltage;
//how fast the battery can be recharged
private float maxRechargeSpeed;
//how fast it's currently being recharged (can be changed, so that
//charging can be slowed down or disabled if there's a shortage of power)
private float rechargeSpeed;
private float maxOutput;
private float lastSentCharge;
public float CurrPowerOutput
{
get;
private set;
}
[Editable, HasDefaultValue(10.0f, true)]
public float MaxOutPut
{
set { maxOutput = value; }
get { return maxOutput; }
}
[HasDefaultValue(10.0f, true), Editable]
public float Capacity
{
get { return capacity; }
set { capacity = Math.Max(value, 1.0f); }
}
[Editable, HasDefaultValue(0.0f, true)]
public float Charge
{
get { return charge; }
set
{
if (!MathUtils.IsValid(value)) return;
charge = MathHelper.Clamp(value, 0.0f, capacity);
if (Math.Abs(charge - lastSentCharge) / capacity > 1.0f)
{
if (GameMain.Server != null) item.CreateServerEvent(this);
lastSentCharge = charge;
}
}
}
[HasDefaultValue(10.0f, true), Editable]
public float RechargeSpeed
{
get { return rechargeSpeed; }
set
{
if (!MathUtils.IsValid(value)) return;
rechargeSpeed = MathHelper.Clamp(value, 0.0f, maxRechargeSpeed);
rechargeSpeed = MathUtils.RoundTowardsClosest(rechargeSpeed, Math.Max(maxRechargeSpeed * 0.1f, 1.0f));
}
}
[HasDefaultValue(10.0f, false), Editable]
public float MaxRechargeSpeed
{
get { return maxRechargeSpeed; }
set { maxRechargeSpeed = Math.Max(value, 1.0f); }
}
public PowerContainer(Item item, XElement element)
: base(item, element)
{
//capacity = ToolBox.GetAttributeFloat(element, "capacity", 10.0f);
//maxRechargeSpeed = ToolBox.GetAttributeFloat(element, "maxinput", 10.0f);
//maxOutput = ToolBox.GetAttributeFloat(element, "maxoutput", 10.0f);
IsActive = true;
if (canBeSelected)
{
var button = new GUIButton(new Rectangle(160, 50, 30,30), "-", "", GuiFrame);
button.OnClicked = (GUIButton btn, object obj) =>
{
RechargeSpeed = rechargeSpeed - maxRechargeSpeed * 0.1f;
if (GameMain.Server != null)
{
item.CreateServerEvent(this);
GameServer.Log(Character.Controlled + " set the recharge speed of " + item.Name + " to " + (int)((rechargeSpeed / maxRechargeSpeed) * 100.0f) + " %", ServerLog.MessageType.ItemInteraction);
}
else if (GameMain.Client != null)
{
item.CreateClientEvent(this);
correctionTimer = CorrectionDelay;
}
return true;
};
button = new GUIButton(new Rectangle(200, 50, 30, 30), "+", "", GuiFrame);
button.OnClicked = (GUIButton btn, object obj) =>
{
RechargeSpeed = rechargeSpeed + maxRechargeSpeed * 0.1f;
if (GameMain.Server != null)
{
item.CreateServerEvent(this);
GameServer.Log(Character.Controlled + " set the recharge speed of " + item.Name + " to " + (int)((rechargeSpeed / maxRechargeSpeed) * 100.0f) + " %", ServerLog.MessageType.ItemInteraction);
}
else if (GameMain.Client != null)
{
item.CreateClientEvent(this);
correctionTimer = CorrectionDelay;
}
return true;
};
}
}
public override bool Pick(Character picker)
{
if (picker == null) return false;
//picker.SelectedConstruction = (picker.SelectedConstruction == item) ? null : item;
return true;
}
public override void Update(float deltaTime, Camera cam)
{
float chargeRatio = (float)(Math.Sqrt(charge / capacity));
float gridPower = 0.0f;
float gridLoad = 0.0f;
//if (item.linkedTo.Count == 0) return;
foreach (Connection c in item.Connections)
{
if (c.Name == "power_in") continue;
foreach (Connection c2 in c.Recipients)
{
PowerTransfer pt = c2.Item.GetComponent<PowerTransfer>();
if (pt == null || !pt.IsActive) continue;
gridLoad += pt.PowerLoad;
gridPower -= pt.CurrPowerConsumption;
}
}
//float gridRate = voltage;
if (chargeRatio > 0.0f)
{
ApplyStatusEffects(ActionType.OnActive, deltaTime, null);
}
//recharge
//if (gridRate >= chargeRate)
//{
if (charge >= capacity)
{
rechargeVoltage = 0.0f;
charge = capacity;
CurrPowerConsumption = 0.0f;
}
else
{
currPowerConsumption = MathHelper.Lerp(currPowerConsumption, rechargeSpeed, 0.05f);
Charge += currPowerConsumption * rechargeVoltage / 3600.0f;
}
//}
//provide power to the grid
if (gridLoad > 0.0f)
{
if (charge <= 0.0f)
{
CurrPowerOutput = 0.0f;
charge = 0.0f;
return;
}
if (gridPower < gridLoad)
{
CurrPowerOutput = MathHelper.Lerp(
CurrPowerOutput,
Math.Min(maxOutput * chargeRatio, gridLoad),
deltaTime);
}
else
{
CurrPowerOutput = MathHelper.Lerp(CurrPowerOutput, 0.0f, deltaTime);
}
Charge -= CurrPowerOutput / 3600.0f;
}
rechargeVoltage = 0.0f;
outputVoltage = 0.0f;
}
public override bool AIOperate(float deltaTime, Character character, AIObjectiveOperateItem objective)
{
RechargeSpeed = maxRechargeSpeed * 0.5f;
return true;
}
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power)
{
if (!connection.IsPower) return;
if (connection.Name == "power_in")
{
rechargeVoltage = power;
}
else
{
outputVoltage = power;
}
}
public void Draw(SpriteBatch spriteBatch, bool editing = false)
{
GUI.DrawRectangle(spriteBatch,
new Vector2(item.DrawPosition.X- 4, -item.DrawPosition.Y),
new Vector2(8, 22), Color.Black);
if (charge > 0)
GUI.DrawRectangle(spriteBatch,
new Vector2(item.DrawPosition.X - 3, -item.DrawPosition.Y + 1 + (20.0f * (1.0f - charge / capacity))),
new Vector2(6, 20 * (charge / capacity)), Color.Green, true);
}
public override void DrawHUD(SpriteBatch spriteBatch, Character character)
{
GuiFrame.Draw(spriteBatch);
int x = GuiFrame.Rect.X;
int y = GuiFrame.Rect.Y;
//GUI.DrawRectangle(spriteBatch, new Rectangle(x, y, width, height), Color.Black, true);
GUI.Font.DrawString(spriteBatch,
"Charge: " + (int)charge + "/" + (int)capacity + " kWm (" + (int)((charge / capacity) * 100.0f) + " %)",
new Vector2(x + 30, y + 30), Color.White);
GUI.Font.DrawString(spriteBatch, "Recharge rate: " + (int)((rechargeSpeed / maxRechargeSpeed) * 100.0f) + " %", new Vector2(x + 30, y + 95), Color.White);
}
public override void AddToGUIUpdateList()
{
GuiFrame.AddToGUIUpdateList();
}
public override void UpdateHUD(Character character)
{
GuiFrame.Update(1.0f / 60.0f);
}
public void ClientWrite(NetBuffer msg, object[] extraData)
{
msg.WriteRangedInteger(0, 10, (int)(rechargeSpeed / MaxRechargeSpeed * 10));
}
public void ServerRead(ClientNetObject type, NetBuffer msg, Client c)
{
float newRechargeSpeed = msg.ReadRangedInteger(0,10) / 10.0f * maxRechargeSpeed;
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);
}
item.CreateServerEvent(this);
}
public void ServerWrite(NetBuffer msg, Client c, object[] extraData = null)
{
msg.WriteRangedInteger(0, 10, (int)(rechargeSpeed / MaxRechargeSpeed * 10));
float chargeRatio = MathHelper.Clamp(charge / capacity, 0.0f, 1.0f);
msg.WriteRangedSingle(chargeRatio, 0.0f, 1.0f, 8);
}
public void ClientRead(ServerNetObject type, NetBuffer msg, float sendingTime)
{
if (correctionTimer > 0.0f)
{
StartDelayedCorrection(type, msg.ExtractBits(4 + 8), sendingTime);
return;
}
RechargeSpeed = msg.ReadRangedInteger(0, 10) / 10.0f * maxRechargeSpeed;
Charge = msg.ReadRangedSingle(0.0f, 1.0f, 8) * capacity;
}
}
}
@@ -0,0 +1,223 @@
using System.Collections.Generic;
using System.Xml.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;
using System.Globalization;
using System.Linq;
namespace Barotrauma.Items.Components
{
class PowerTransfer : Powered
{
static float fullPower;
static float fullLoad;
//private bool updated;
private int updateTimer;
const float FireProbability = 0.15f;
//affects how fast changes in power/load are carried over the grid
static float inertia = 5.0f;
static HashSet<Powered> connectedList = new HashSet<Powered>();
private List<Connection> powerConnections;
private float powerLoad;
public float PowerLoad
{
get { return powerLoad; }
}
public PowerTransfer(Item item, XElement element)
: base(item, element)
{
IsActive = true;
powerConnections = new List<Connection>();
}
public override void Update(float deltaTime, Camera cam)
{
if (updateTimer > 0)
{
//this junction box has already been updated this frame
updateTimer--;
return;
}
//reset and recalculate the power generated/consumed
//by the constructions connected to the grid
fullPower = 0.0f;
fullLoad = 0.0f;
connectedList.Clear();
CheckJunctions(deltaTime);
updateTimer = 0;
foreach (Powered p in connectedList)
{
PowerTransfer pt = p as PowerTransfer;
if (pt == null) continue;
pt.powerLoad += (fullLoad - pt.powerLoad) / inertia;
pt.currPowerConsumption += (-fullPower - pt.currPowerConsumption) / inertia;
pt.Item.SendSignal(0, "", "power", null, fullPower / Math.Max(fullLoad, 1.0f));
pt.Item.SendSignal(0, "", "power_out", null, fullPower / Math.Max(fullLoad, 1.0f));
//damage the item if voltage is too high
//(except if running as a client)
if (GameMain.Client != null) continue;
if (-pt.currPowerConsumption < Math.Max(pt.powerLoad * Rand.Range(1.9f,2.1f), 200.0f)) continue;
float prevCondition = pt.item.Condition;
pt.item.Condition -= deltaTime * 10.0f;
if (pt.item.Condition <= 0.0f && prevCondition > 0.0f)
{
sparkSounds[Rand.Int(sparkSounds.Length)].Play(1.0f, 600.0f, pt.item.WorldPosition);
Vector2 baseVel = Rand.Vector(300.0f);
for (int i = 0; i < 10; i++)
{
var particle = GameMain.ParticleManager.CreateParticle("spark", pt.item.WorldPosition,
baseVel + Rand.Vector(100.0f), 0.0f, item.CurrentHull);
if (particle != null) particle.Size *= Rand.Range(0.5f, 1.0f);
}
if (FireProbability > 0.0f && Rand.Int((int)(1.0f / FireProbability)) == 1)
{
new FireSource(pt.item.WorldPosition);
}
}
}
}
public override bool Pick(Character picker)
{
return picker != null;
}
//a recursive function that goes through all the junctions and adds up
//all the generated/consumed power of the constructions connected to the grid
private void CheckJunctions(float deltaTime)
{
updateTimer = 1;
connectedList.Add(this);
ApplyStatusEffects(ActionType.OnActive, deltaTime, null);
foreach (Connection c in powerConnections)
{
var recipients = c.Recipients;
foreach (Connection recipient in recipients)
{
if (recipient == null) continue;
Item it = recipient.Item;
if (it == null) continue;
if (it.Condition <= 0.0f) continue;
foreach (Powered powered in it.GetComponents<Powered>())
{
if (powered == null || !powered.IsActive) continue;
if (connectedList.Contains(powered)) continue;
PowerTransfer powerTransfer = powered as PowerTransfer;
if (powerTransfer != null)
{
powerTransfer.CheckJunctions(deltaTime);
continue;
}
PowerContainer powerContainer = powered as PowerContainer;
if (powerContainer != null)
{
if (recipient.Name == "power_in")
{
fullLoad += powerContainer.CurrPowerConsumption;
}
else
{
fullPower += powerContainer.CurrPowerOutput;
}
}
else
{
connectedList.Add(powered);
//positive power consumption = the construction requires power -> increase load
if (powered.CurrPowerConsumption > 0.0f)
{
fullLoad += powered.CurrPowerConsumption;
}
else if (powered.CurrPowerConsumption < 0.0f)
//negative power consumption = the construction is a
//generator/battery or another junction box
{
fullPower -= powered.CurrPowerConsumption;
}
}
}
}
}
}
public override void DrawHUD(SpriteBatch spriteBatch, Character character)
{
if (!canBeSelected) return;
int x = GuiFrame.Rect.X;
int y = GuiFrame.Rect.Y;
GuiFrame.Draw(spriteBatch);
GUI.Font.DrawString(spriteBatch, "Power: " + (int)(-currPowerConsumption) + " kW", new Vector2(x + 30, y + 30), Color.White);
GUI.Font.DrawString(spriteBatch, "Load: " + (int)powerLoad + " kW", new Vector2(x + 30, y + 100), Color.White);
}
public override void AddToGUIUpdateList()
{
GuiFrame.AddToGUIUpdateList();
}
public override void UpdateHUD(Character character)
{
GuiFrame.Update(1.0f / 60.0f);
}
public override void OnMapLoaded()
{
var connections = item.Connections;
if (connections == null)
{
IsActive = false;
return;
}
powerConnections = connections.FindAll(c => c.IsPower);
if (powerConnections.Count == 0) IsActive = false;
}
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power)
{
base.ReceiveSignal(stepsTaken, signal, connection, source, sender, power);
if (connection.Name.Length > 5 && connection.Name.Substring(0, 6).ToLowerInvariant() == "signal")
{
connection.SendSignal(stepsTaken, signal, source, sender, 0.0f);
}
}
}
}
@@ -0,0 +1,111 @@
using System;
using System.Xml.Linq;
namespace Barotrauma.Items.Components
{
class Powered : ItemComponent
{
protected static Sound[] sparkSounds;
//the amount of power CURRENTLY consumed by the item
//negative values mean that the item is providing power to connected items
protected float currPowerConsumption;
//current voltage of the item (load / power)
protected float voltage;
//the minimum voltage required for the item to work
protected float minVoltage;
//the maximum amount of power the item can draw from connected items
protected float powerConsumption;
private bool powerOnSoundPlayed;
private static Sound powerOnSound;
[Editable, HasDefaultValue(0.5f, true)]
public float MinVoltage
{
get { return minVoltage; }
set { minVoltage = value; }
}
[Editable, HasDefaultValue(0.0f, true)]
public float PowerConsumption
{
get { return powerConsumption; }
set { powerConsumption = value; }
}
[HasDefaultValue(false,true)]
public override bool IsActive
{
get { return base.IsActive; }
set
{
base.IsActive = value;
if (!value) currPowerConsumption = 0.0f;
}
}
[HasDefaultValue(0.0f, true)]
public float CurrPowerConsumption
{
get {return currPowerConsumption; }
set { currPowerConsumption = value; }
}
[HasDefaultValue(0.0f, true)]
public float Voltage
{
get { return voltage; }
set { voltage = Math.Max(0.0f, value); }
}
public Powered(Item item, XElement element)
: base(item, element)
{
if (powerOnSound == null)
{
powerOnSound = Sound.Load("Content/Items/Electricity/powerOn.ogg", false);
}
if (sparkSounds == null)
{
sparkSounds = new Sound[4];
for (int i = 0; i < 4; i++)
{
sparkSounds[i] = Sound.Load("Content/Items/Electricity/zap" + (i + 1) + ".ogg", false);
}
}
}
public override void ReceiveSignal(int stepsTaken, string signal, Connection connection, Item source, Character sender, float power = 0)
{
if (currPowerConsumption == 0.0f) voltage = 0.0f;
if (connection.IsPower) voltage = power;
}
public override void Update(float deltaTime, Camera cam)
{
if (currPowerConsumption == 0.0f) return;
if (voltage > minVoltage)
{
if (!powerOnSoundPlayed)
{
powerOnSound.Play(1.0f, 600.0f, item.WorldPosition);
powerOnSoundPlayed = true;
}
}
else if (voltage < 0.1f)
{
powerOnSoundPlayed = false;
}
}
}
}