diff --git a/config/worldserver.ini.dist b/config/worldserver.ini.dist index eb12d0e0..a62c7603 100644 --- a/config/worldserver.ini.dist +++ b/config/worldserver.ini.dist @@ -1,9 +1,104 @@ ####################################### # PSForever Server configuration file # ####################################### + +################################################################################################### +# EXAMPLE CONFIG +# +# Variable (type) +# Description: Brief description what the variable is doing. +# Important: Annotation for important things about this variable. +# Example: "Example, i.e. if the value is a string" +# Range: [0, 10] - (Disabled, Enabled) +# Default: 10 - (Enabled|Comment|Variable name in case of grouped config options) +# 0 - (Disabled|Comment|Variable name in case of grouped config options) +# +# Note to developers: +# - Copy this example to keep the formatting. +# - Line breaks should be at column 100. +################################################################################################### + +################################################################################################### +# WORLDSERVER SETTINGS +################################################################################################### + [worldserver] + +# ListeningPort (int) +# Description: The UDP listening port for the worldserver. +# Important: Must be different from the loginserver.ListeningPort. Ports below 1024 are +# privileged on Linux and may require root. +# Range: [1, 65535] - (UDP port 1, UDP port 65535) +# Default: 51001 - (Listen on UDP port 51001) + ListeningPort = 51001 +################################################################################################### +# LOGINSERVER SETTINGS +################################################################################################### + [loginserver] + +# ListeningPort (int) +# Description: The UDP listening port for the loginserver. +# Important: Must be different from the worldserver.ListeningPort. Ports below 1024 are +# privileged on Linux and may require root. +# Range: [1, 65535] - (UDP port 1, UDP port 65535) +# Default: 51000 - (Listen on UDP port 5100) + ListeningPort = 51000 +################################################################################################### +# DEVELOPER SETTINGS +# - NETWORK SIMULATOR +################################################################################################### + +[developer] + +################################################################################################### +# NETWORK SIMULATOR +# +# NetSim.Active (boolean) +# Description: Enable artificial packet unreliability. Used for development testing. +# Active equally on upstream and downstream packets. +# Important: DO NOT enable on servers with a high packet rate as buffering increases +# the memory load of the server and it will (by design) affect performance. +# Default: no - (Disabled) +# yes - (Enabled) +NetSim.Active = no + +# NetSim.Loss (float) +# Description: The percentage of outgoing and incoming packets that are dropped. +# Range: [0.0, 1.0] - (0% loss, 100% packet loss) +# Default: 0.02 - (2% packet loss) + +NetSim.Loss = 0.02 + +# NetSim.Delay (time) +# Description: The time a packet is buffered before being delivered to simulate delay. +# The artificial delay is in addition to any real network latency. +# Important: Longer delays will lead to larger packet buffering, which may cause +# out-of-memory errors depending on packet rate. +# Range: [0, 2 seconds] - (No delay, 2 seconds delay) +# Default: 150 milliseconds - (Packets lag for 150 milliseconds) + +NetSim.Delay = 150 milliseconds + +# NetSim.ReorderChance (float) +# Description: The percentage chance that a packet will be ordered randomly in the delay +# buffer. If the NetSim.Delay is too small then packets won't be reordered. +# Range: [0.0, 1.0] - (No packet reordering, reorder every packet) +# Default: 0.005 - (0.5% chance of a packet being reordered) + +NetSim.ReorderChance = 0.005 + +# NetSim.ReorderTime (time) +# Description: If a packet is reordered, the maximum time in the future or the past where +# it will randomly appear. +# Range: [0, 2 seconds] - (No packet reordering, randomly shift +/- 2 seconds) +# Default: 150 milliseconds - (+/- 150 milliseconds) + +NetSim.ReorderTime = 150 milliseconds + +# +################################################################################################### diff --git a/pslogin/src/main/scala/PsLogin.scala b/pslogin/src/main/scala/PsLogin.scala index eb7db921..7a62a3c2 100644 --- a/pslogin/src/main/scala/PsLogin.scala +++ b/pslogin/src/main/scala/PsLogin.scala @@ -242,16 +242,19 @@ object PsLogin { val loginServerPort = WorldConfig.Get[Int]("loginserver.ListeningPort") val worldServerPort = WorldConfig.Get[Int]("worldserver.ListeningPort") - // Uncomment for network simulation - // TODO: make this config or command flag - /* - val netParams = NetworkSimulatorParameters( - packetLoss = 0.02, - packetDelay = 500, - packetReorderingChance = 0.005, - packetReorderingTime = 400 - ) - */ + val netSim : Option[NetworkSimulatorParameters] = WorldConfig.Get[Boolean]("developer.NetSim.Active") match { + case true => + val params = NetworkSimulatorParameters( + WorldConfig.Get[Float]("developer.NetSim.Loss"), + WorldConfig.Get[Duration]("developer.NetSim.Delay").toMillis, + WorldConfig.Get[Float]("developer.NetSim.ReorderChance"), + WorldConfig.Get[Duration]("developer.NetSim.ReorderTime").toMillis + ) + logger.warn("NetSim is active") + logger.warn(params.toString) + Some(params) + case false => None + } val continentList = createContinents() val serviceManager = ServiceManager.boot @@ -283,8 +286,8 @@ object PsLogin { /** Create two actors for handling the login and world server endpoints */ loginRouter = Props(new SessionRouter("Login", loginTemplate)) worldRouter = Props(new SessionRouter("World", worldTemplate)) - loginListener = system.actorOf(Props(new UdpListener(loginRouter, "login-session-router", LoginConfig.serverIpAddress, loginServerPort, None)), "login-udp-endpoint") - worldListener = system.actorOf(Props(new UdpListener(worldRouter, "world-session-router", LoginConfig.serverIpAddress, worldServerPort, None)), "world-udp-endpoint") + loginListener = system.actorOf(Props(new UdpListener(loginRouter, "login-session-router", LoginConfig.serverIpAddress, loginServerPort, netSim)), "login-udp-endpoint") + worldListener = system.actorOf(Props(new UdpListener(worldRouter, "world-session-router", LoginConfig.serverIpAddress, worldServerPort, netSim)), "world-udp-endpoint") logger.info(s"NOTE: Set client.ini to point to ${LoginConfig.serverIpAddress.getHostAddress}:$loginServerPort") diff --git a/pslogin/src/main/scala/UdpNetworkSimulator.scala b/pslogin/src/main/scala/UdpNetworkSimulator.scala index c79ca37d..4c377326 100644 --- a/pslogin/src/main/scala/UdpNetworkSimulator.scala +++ b/pslogin/src/main/scala/UdpNetworkSimulator.scala @@ -16,13 +16,16 @@ import scala.concurrent.duration._ * forward or backwards in time) */ case class NetworkSimulatorParameters(packetLoss : Double, - packetDelay : Int, + packetDelay : Long, packetReorderingChance : Double, - packetReorderingTime : Int) { + packetReorderingTime : Long) { assert(packetLoss >= 0.0 && packetLoss <= 1.0) assert(packetDelay >= 0) assert(packetReorderingChance >= 0.0 && packetReorderingChance <= 1.0) assert(packetReorderingTime >= 0) + + override def toString = "NetSimParams: loss %.2f%% / delay %dms / reorder %.2f%% / reorder +/- %dms".format( + packetLoss*100, packetDelay, packetReorderingChance*100, packetReorderingTime); } diff --git a/pslogin/src/main/scala/WorldConfig.scala b/pslogin/src/main/scala/WorldConfig.scala index 5f5bff41..e6de5ae7 100644 --- a/pslogin/src/main/scala/WorldConfig.scala +++ b/pslogin/src/main/scala/WorldConfig.scala @@ -1,5 +1,6 @@ // Copyright (c) 2019 PSForever import net.psforever.config._ +import scala.concurrent.duration._ object WorldConfig extends ConfigParser { protected var config_map : Map[String, Any] = Map() @@ -10,6 +11,13 @@ object WorldConfig extends ConfigParser { ), ConfigSection("worldserver", ConfigEntryInt("ListeningPort", 51001, Constraints.min(1), Constraints.max(65535)) + ), + ConfigSection("developer", + ConfigEntryBool ("NetSim.Active", false), + ConfigEntryFloat("NetSim.Loss", 0.02f, Constraints.min(0.0f), Constraints.max(1.0f)), + ConfigEntryTime ("NetSim.Delay", 150 milliseconds, Constraints.min(0 seconds), Constraints.max(2 seconds)), + ConfigEntryFloat("NetSim.ReorderChance", 0.005f, Constraints.min(0.0f), Constraints.max(1.0f)), + ConfigEntryTime ("NetSim.ReorderTime", 150 milliseconds, Constraints.min(0 seconds), Constraints.max(2 seconds)) ) )