protected override void NetMsgInput(NetworkChunk packet, Unpacker unpacker, int clientId) { Clients[clientId].LastAckedSnapshot = unpacker.GetInt(); var intendedTick = unpacker.GetInt(); var size = unpacker.GetInt(); if (unpacker.Error || size / sizeof(int) > BaseServerClient.MAX_INPUT_SIZE) { return; } if (Clients[clientId].LastAckedSnapshot > 0) { Clients[clientId].SnapRate = SnapRate.FULL; } if (Clients[clientId].SnapshotStorage.Get( Clients[clientId].LastAckedSnapshot, out var tagTime, out var _)) { Clients[clientId].Latency = (int)(((Time.Get() - tagTime) * 1000) / Time.Freq()); } if (intendedTick > Clients[clientId].LastInputTick) { var timeLeft = (TickStartTime(intendedTick) - Time.Get()) * 1000 / Time.Freq(); var msg = new MsgPacker((int)NetworkMessages.SV_INPUT_TIMING); msg.AddInt(intendedTick); msg.AddInt((int)timeLeft); SendMsgEx(msg, MsgFlags.NONE, clientId, true); } Clients[clientId].LastInputTick = intendedTick; var input = Clients[clientId].Inputs[Clients[clientId].CurrentInput]; if (intendedTick <= Tick) { intendedTick = Tick + 1; } var data = new int[size / sizeof(int)]; for (var i = 0; i < data.Length; i++) { data[i] = unpacker.GetInt(); } input.Tick = intendedTick; input.PlayerInput.Deserialize(data, 0); Clients[clientId].CurrentInput++; Clients[clientId].CurrentInput %= Clients[clientId].Inputs.Length; if (Clients[clientId].State == ServerClientState.IN_GAME) { GameContext.OnClientDirectInput(clientId, input.PlayerInput); } }
private async Task SendChunkBuffers(NetworkChunk chunk) { BinaryPrimitives.WriteInt32BigEndian(outgoingHeader.AsSpan(LENGTH_INDEX), chunk.Data.Length); outgoingHeader[INSTRUCTION_INDEX] = chunk.Instruction; await SendBuffer(outgoingHeader).ConfigureAwait(false); await SendBuffer(chunk.Data).ConfigureAwait(false); }
protected override void NetMsgInfo(NetworkChunk packet, Unpacker unpacker, int clientId) { if (Clients[clientId].State != ServerClientState.AUTH) { return; } var version = unpacker.GetString(SanitizeType.SANITIZE_CC); if (string.IsNullOrEmpty(version) || !version.StartsWith(GameContext.NetVersion)) { NetworkServer.Drop(clientId, $"Wrong version. Server is running '{GameContext.NetVersion}' and client '{version}'"); return; } var password = unpacker.GetString(SanitizeType.SANITIZE_CC); if (!string.IsNullOrEmpty(Config["Password"]) && password != Config["Password"]) { NetworkServer.Drop(clientId, "Wrong password"); return; } if (clientId >= NetworkServer.ServerConfig.MaxClients - Config["SvReservedSlots"] && !string.IsNullOrEmpty(Config["SvReservedSlotsPass"]) && password != Config["SvReservedSlotsPass"]) { NetworkServer.Drop(clientId, "This server is full"); return; } Clients[clientId].State = ServerClientState.CONNECTING; SendMap(clientId); }
protected override void NetMsgEnterGame(NetworkChunk packet, Unpacker unpacker, int clientId) { if (Clients[clientId].State != ServerClientState.READY || !GameContext.IsClientReady(clientId)) { return; } Console.Print(OutputLevel.STANDARD, "server", $"player has entered the game. ClientID={clientId} addr={NetworkServer.ClientEndPoint(clientId)}"); Clients[clientId].State = ServerClientState.IN_GAME; GameContext.OnClientEnter(clientId); }
public override bool SendMsgEx(MsgPacker msg, MsgFlags flags, int clientId, bool system) { if (msg == null) { return(false); } var packet = new NetworkChunk() { ClientId = clientId, DataSize = msg.Size(), Data = msg.Data(), }; packet.Data[0] <<= 1; if (system) { packet.Data[0] |= 1; } if (flags.HasFlag(MsgFlags.VITAL)) { packet.Flags |= SendFlags.VITAL; } if (flags.HasFlag(MsgFlags.FLUSH)) { packet.Flags |= SendFlags.FLUSH; } if (!flags.HasFlag(MsgFlags.NOSEND)) { if (clientId == -1) { for (var i = 0; i < Clients.Length; i++) { if (Clients[i].State != ServerClientState.IN_GAME) { continue; } packet.ClientId = i; NetworkServer.Send(packet); } } else { NetworkServer.Send(packet); } } return(true); }
public async Task SendChunk(NetworkChunk chunk) { Status currentStatus = (Status)Interlocked.CompareExchange(ref status, 0, 0); if (currentStatus is Status.Running) { await outgoing.Writer.WriteAsync(chunk).ConfigureAwait(false); } else { throw new InvalidOperationException($"Cannot send chunk. {nameof(currentStatus)} is {nameof(Status)}.{currentStatus}"); } }
protected override void NetMsgReady(NetworkChunk packet, Unpacker unpacker, int clientId) { if (Clients[clientId].State != ServerClientState.CONNECTING) { return; } Console.Print(OutputLevel.ADDINFO, "server", $"player is ready. ClientID={clientId} addr={NetworkServer.ClientEndPoint(clientId)}"); Clients[clientId].State = ServerClientState.READY; GameContext.OnClientConnected(clientId); var msg = new MsgPacker((int)NetworkMessages.SV_CON_READY); SendMsgEx(msg, MsgFlags.VITAL | MsgFlags.FLUSH, clientId, true); }
protected override void NetMsgRequestMapData(NetworkChunk packet, Unpacker unpacker, int clientId) { if (Clients[clientId].State < ServerClientState.CONNECTING) { return; } var chunk = unpacker.GetInt(); var chunkSize = 1024 - 128; var offset = chunk * chunkSize; var last = 0; _lastAsk[clientId] = chunk; _lastAskTick[clientId] = Tick; if (chunk == 0) { _lastSent[clientId] = 0; } if (chunk < 0 || offset > CurrentMap.Size) { return; } if (offset + chunkSize >= CurrentMap.Size) { chunkSize = CurrentMap.Size - offset; last = 1; if (chunkSize < 0) { chunkSize = 0; } } if (_lastSent[clientId] < chunk + Config["SvMapWindow"] && Config["SvFastDownload"]) { return; } SendMapData(last, chunk, chunkSize, offset, clientId); }
private async Task ProcessOutgoing() { while (Interlocked.CompareExchange(ref status, 0, 0) == (int)Status.Running) { Task <NetworkChunk> chunkTask = WaitForOutgoingChunk(); Task delayTask = Task.Delay(timeoutOptions.Period); Task firstToFinsih = await Task.WhenAny(chunkTask, delayTask).ConfigureAwait(false); if (ReferenceEquals(firstToFinsih, chunkTask)) { NetworkChunk chunk = await chunkTask.ConfigureAwait(false); await SendChunkBuffers(chunk).ConfigureAwait(false); } else { await SendBuffer(KEEP_ALIVE_HEADER).ConfigureAwait(false); } } }
public void OnPacket(NetworkChunk packet) { // get servers from masterserver if (packet.DataSize >= MasterServerPackets.SERVERBROWSE_LIST.Length + 1 && packet.Data.ArrayCompare( MasterServerPackets.SERVERBROWSE_LIST, MasterServerPackets.SERVERBROWSE_LIST.Length)) { if (!IsMasterServer(packet.EndPoint)) { return; } var list = packet.Data.ReadStructs <MasterServerAddr>( MasterServerPackets.SERVERBROWSE_LIST.Length); for (var i = 0; i < list.Length; i++) { IPAddress ip; var port = (list[i].Port[0] << 8) | list[i].Port[1]; if (_IPV4Mapping.ArrayCompare(list[i].Ip, _IPV4Mapping.Length)) { ip = new IPAddress(new[] { list[i].Ip[12], list[i].Ip[13], list[i].Ip[14], list[i].Ip[15], }); } else { ip = new IPAddress(list[i].Ip); } var serverAddr = new IPEndPoint(ip, port); ServersSnapshot.AddServer(serverAddr); OnServerAddrReceived(serverAddr); } } }
protected override void NetMsgRconAuth(NetworkChunk packet, Unpacker unpacker, int clientId) { var login = unpacker.GetString(); var password = unpacker.GetString(); SendRconLine(clientId, password); if (!packet.Flags.HasFlag(SendFlags.VITAL) || unpacker.Error) { return; } if (string.IsNullOrEmpty(Config["SvRconPassword"]) && string.IsNullOrEmpty(Config["SvRconModPassword"])) { SendRconLine(clientId, "No rcon password set on server. Set sv_rcon_password and/or sv_rcon_mod_password to enable the remote console."); } var authed = false; if (password == Config["SvRconPassword"]) { authed = true; } else if (password == Config["SvRconModPassword"]) { authed = true; } if (authed) { var msg = new MsgPacker((int)NetworkMessages.SV_RCON_AUTH_STATUS); msg.AddInt(1); msg.AddInt(1); SendMsgEx(msg, MsgFlags.VITAL, clientId, true); } }
public NetworkChunkRequest(NetworkChunk Chunk) { Location = Chunk.ChunkCoords; }
protected override void NetMsgPing(NetworkChunk packet, Unpacker unpacker, int clientId) { var msg = new MsgPacker((int)NetworkMessages.PING_REPLY); SendMsgEx(msg, 0, clientId, true); }
protected override void NetMsgRconCmd(NetworkChunk packet, Unpacker unpacker, int clientId) { }
public NetworkChunkResponse() { Chunk = new NetworkChunk(Game.World.Realm, new Vector3i()); }
public NetworkChunkResponse(NetworkChunk Chunk) { this.Chunk = Chunk; }
protected abstract void NetMsgInfo(NetworkChunk packet, Unpacker unpacker, int clientId);
protected abstract void NetMsgRequestMapData(NetworkChunk packet, Unpacker unpacker, int clientId);
protected abstract void NetMsgEnterGame(NetworkChunk packet, Unpacker unpacker, int clientId);
protected abstract void ProcessClientPacket(NetworkChunk packet);
protected override void ProcessClientPacket(NetworkChunk packet) { var clientId = packet.ClientId; var unpacker = new Unpacker(); unpacker.Reset(packet.Data, packet.DataSize); var msg = unpacker.GetInt(); var isSystemMsg = (msg & 1) != 0; msg >>= 1; if (unpacker.Error) { return; } if (Config["SvNetlimit"] && !(isSystemMsg && msg == (int)NetworkMessages.CL_REQUEST_MAP_DATA)) { var now = Time.Get(); var diff = now - Clients[clientId].TrafficSince; var alpha = Config["SvNetlimitAlpha"] / 100f; var limit = (float)Config["SvNetlimit"] * 1024 / Time.Freq(); if (Clients[clientId].Traffic > limit) { NetworkBan.BanAddr(packet.EndPoint, 600, "Stressing network"); return; } if (diff > 100) { Clients[clientId].Traffic = (int)(alpha * ((float)packet.DataSize / diff) + (1.0f - alpha) * Clients[clientId].Traffic); Clients[clientId].TrafficSince = now; } } if (isSystemMsg) { var networkMsg = (NetworkMessages)msg; switch (networkMsg) { case NetworkMessages.CL_INFO: NetMsgInfo(packet, unpacker, clientId); break; case NetworkMessages.CL_REQUEST_MAP_DATA: NetMsgRequestMapData(packet, unpacker, clientId); break; case NetworkMessages.CL_READY: NetMsgReady(packet, unpacker, clientId); break; case NetworkMessages.CL_ENTERGAME: NetMsgEnterGame(packet, unpacker, clientId); break; case NetworkMessages.CL_INPUT: NetMsgInput(packet, unpacker, clientId); break; case NetworkMessages.CL_RCON_CMD: NetMsgRconCmd(packet, unpacker, clientId); break; case NetworkMessages.CL_RCON_AUTH: NetMsgRconAuth(packet, unpacker, clientId); break; case NetworkMessages.PING: NetMsgPing(packet, unpacker, clientId); break; default: Console.Print(OutputLevel.DEBUG, "server", $"strange message clientId={clientId} msg={msg} data_size={packet.DataSize}"); break; } } else if (Clients[clientId].State >= ServerClientState.READY) { GameContext.OnMessage(msg, unpacker, clientId); } }