i live in spain but the S is silent
All checks were successful
Build and push image / Build (push) Successful in 49s
All checks were successful
Build and push image / Build (push) Successful in 49s
This commit is contained in:
@@ -0,0 +1,142 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace ksBroadcastingNetwork
|
||||
{
|
||||
public class ACCUdpRemoteClient : IDisposable
|
||||
{
|
||||
private UdpClient _client;
|
||||
private Task _listenerTask;
|
||||
public BroadcastingNetworkProtocol MessageHandler { get; }
|
||||
public string IpPort { get; }
|
||||
public string DisplayName { get; }
|
||||
public string ConnectionPassword { get; }
|
||||
public string CommandPassword { get; }
|
||||
public int MsRealtimeUpdateInterval { get; }
|
||||
|
||||
/// <summary>
|
||||
/// To get the events delivered inside the UI thread, just create this object from the UI thread/synchronization context.
|
||||
/// </summary>
|
||||
public ACCUdpRemoteClient(string ip, int port, string displayName, string connectionPassword, string commandPassword, int msRealtimeUpdateInterval)
|
||||
{
|
||||
IpPort = $"{ip}:{port}";
|
||||
MessageHandler = new BroadcastingNetworkProtocol(IpPort, Send);
|
||||
_client = new UdpClient();
|
||||
_client.Connect(ip, port);
|
||||
|
||||
DisplayName = displayName;
|
||||
ConnectionPassword = connectionPassword;
|
||||
CommandPassword = commandPassword;
|
||||
MsRealtimeUpdateInterval = msRealtimeUpdateInterval;
|
||||
|
||||
_listenerTask = ConnectAndRun();
|
||||
}
|
||||
|
||||
private void Send(byte[] payload)
|
||||
{
|
||||
var sent = _client.Send(payload, payload.Length);
|
||||
}
|
||||
|
||||
public void Shutdown()
|
||||
{
|
||||
ShutdownAsnyc().ContinueWith(t =>
|
||||
{
|
||||
if (t.Exception?.InnerExceptions?.Any() == true)
|
||||
System.Diagnostics.Debug.WriteLine($"Client shut down with {t.Exception.InnerExceptions.Count} errors");
|
||||
else
|
||||
System.Diagnostics.Debug.WriteLine("Client shut down asynchronously");
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
public async Task ShutdownAsnyc()
|
||||
{
|
||||
if (_listenerTask != null && !_listenerTask.IsCompleted)
|
||||
{
|
||||
MessageHandler.Disconnect();
|
||||
_client.Close();
|
||||
_client = null;
|
||||
await _listenerTask;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ConnectAndRun()
|
||||
{
|
||||
MessageHandler.RequestConnection(DisplayName, ConnectionPassword, MsRealtimeUpdateInterval, CommandPassword);
|
||||
while (_client != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
var udpPacket = await _client.ReceiveAsync();
|
||||
using (var ms = new System.IO.MemoryStream(udpPacket.Buffer))
|
||||
using (var reader = new System.IO.BinaryReader(ms))
|
||||
{
|
||||
MessageHandler.ProcessMessage(reader);
|
||||
}
|
||||
}
|
||||
catch (ObjectDisposedException)
|
||||
{
|
||||
// Shutdown happened
|
||||
break;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Other exceptions
|
||||
System.Diagnostics.Debug.WriteLine(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#region IDisposable Support
|
||||
private bool disposedValue = false; // To detect redundant calls
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (!disposedValue)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_client != null)
|
||||
{
|
||||
_client.Close();
|
||||
_client.Dispose();
|
||||
_client = null;
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine(ex);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: free unmanaged resources (unmanaged objects) and override a finalizer below.
|
||||
// TODO: set large fields to null.
|
||||
|
||||
disposedValue = true;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: override a finalizer only if Dispose(bool disposing) above has code to free unmanaged resources.
|
||||
// ~ACCUdpRemoteClient() {
|
||||
// // Do not change this code. Put cleanup code in Dispose(bool disposing) above.
|
||||
// Dispose(false);
|
||||
// }
|
||||
|
||||
// This code added to correctly implement the disposable pattern.
|
||||
public void Dispose()
|
||||
{
|
||||
// Do not change this code. Put cleanup code in Dispose(bool disposing) above.
|
||||
Dispose(true);
|
||||
// TODO: uncomment the following line if the finalizer is overridden above.
|
||||
// GC.SuppressFinalize(this);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
@@ -0,0 +1,159 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace ksBroadcastingNetwork
|
||||
{
|
||||
public enum DriverCategory
|
||||
{
|
||||
Platinum = 3,
|
||||
Gold = 2,
|
||||
Silver = 1,
|
||||
Bronze = 0,
|
||||
Error = 255
|
||||
}
|
||||
|
||||
public enum LapType
|
||||
{
|
||||
ERROR = 0,
|
||||
Outlap = 1,
|
||||
Regular = 2,
|
||||
Inlap = 3
|
||||
}
|
||||
|
||||
public enum CarLocationEnum
|
||||
{
|
||||
NONE = 0,
|
||||
Track = 1,
|
||||
Pitlane = 2,
|
||||
PitEntry = 3,
|
||||
PitExit = 4
|
||||
}
|
||||
|
||||
public enum SessionPhase
|
||||
{
|
||||
NONE = 0,
|
||||
Starting = 1,
|
||||
PreFormation = 2,
|
||||
FormationLap = 3,
|
||||
PreSession = 4,
|
||||
Session = 5,
|
||||
SessionOver = 6,
|
||||
PostSession = 7,
|
||||
ResultUI = 8
|
||||
};
|
||||
public enum RaceSessionType
|
||||
{
|
||||
Practice = 0,
|
||||
Qualifying = 4,
|
||||
Superpole = 9,
|
||||
Race = 10,
|
||||
Hotlap = 11,
|
||||
Hotstint = 12,
|
||||
HotlapSuperpole = 13,
|
||||
Replay = 14
|
||||
};
|
||||
|
||||
public enum BroadcastingCarEventType
|
||||
{
|
||||
None = 0,
|
||||
GreenFlag = 1,
|
||||
SessionOver = 2,
|
||||
PenaltyCommMsg = 3,
|
||||
Accident = 4,
|
||||
LapCompleted = 5,
|
||||
BestSessionLap = 6,
|
||||
BestPersonalLap = 7
|
||||
};
|
||||
|
||||
public enum NationalityEnum
|
||||
{
|
||||
Any = 0,
|
||||
Italy = 1,
|
||||
Germany = 2,
|
||||
France = 3,
|
||||
Spain = 4,
|
||||
GreatBritain = 5,
|
||||
Hungary = 6,
|
||||
Belgium = 7,
|
||||
Switzerland = 8,
|
||||
Austria = 9,
|
||||
Russia = 10,
|
||||
Thailand = 11,
|
||||
Netherlands = 12,
|
||||
Poland = 13,
|
||||
Argentina = 14,
|
||||
Monaco = 15,
|
||||
Ireland = 16,
|
||||
Brazil = 17,
|
||||
SouthAfrica = 18,
|
||||
PuertoRico = 19,
|
||||
Slovakia = 20,
|
||||
Oman = 21,
|
||||
Greece = 22,
|
||||
SaudiArabia = 23,
|
||||
Norway = 24,
|
||||
Turkey = 25,
|
||||
SouthKorea = 26,
|
||||
Lebanon = 27,
|
||||
Armenia = 28,
|
||||
Mexico = 29,
|
||||
Sweden = 30,
|
||||
Finland = 31,
|
||||
Denmark = 32,
|
||||
Croatia = 33,
|
||||
Canada = 34,
|
||||
China = 35,
|
||||
Portugal = 36,
|
||||
Singapore = 37,
|
||||
Indonesia = 38,
|
||||
USA = 39,
|
||||
NewZealand = 40,
|
||||
Australia = 41,
|
||||
SanMarino = 42,
|
||||
UAE = 43,
|
||||
Luxembourg = 44,
|
||||
Kuwait = 45,
|
||||
HongKong = 46,
|
||||
Colombia = 47,
|
||||
Japan = 48,
|
||||
Andorra = 49,
|
||||
Azerbaijan = 50,
|
||||
Bulgaria = 51,
|
||||
Cuba = 52,
|
||||
CzechRepublic = 53,
|
||||
Estonia = 54,
|
||||
Georgia = 55,
|
||||
India = 56,
|
||||
Israel = 57,
|
||||
Jamaica = 58,
|
||||
Latvia = 59,
|
||||
Lithuania = 60,
|
||||
Macau = 61,
|
||||
Malaysia = 62,
|
||||
Nepal = 63,
|
||||
NewCaledonia = 64,
|
||||
Nigeria = 65,
|
||||
NorthernIreland = 66,
|
||||
PapuaNewGuinea = 67,
|
||||
Philippines = 68,
|
||||
Qatar = 69,
|
||||
Romania = 70,
|
||||
Scotland = 71,
|
||||
Serbia = 72,
|
||||
Slovenia = 73,
|
||||
Taiwan = 74,
|
||||
Ukraine = 75,
|
||||
Venezuela = 76,
|
||||
Wales = 77,
|
||||
Iran = 78,
|
||||
Bahrain = 79,
|
||||
Zimbabwe = 80,
|
||||
ChineseTaipei = 81,
|
||||
Chile = 82,
|
||||
Uruguay = 83,
|
||||
Madagascar = 84
|
||||
};
|
||||
}
|
@@ -0,0 +1,516 @@
|
||||
using ksBroadcastingNetwork.Structs;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace ksBroadcastingNetwork
|
||||
{
|
||||
public enum OutboundMessageTypes : byte
|
||||
{
|
||||
REGISTER_COMMAND_APPLICATION = 1,
|
||||
UNREGISTER_COMMAND_APPLICATION = 9,
|
||||
|
||||
REQUEST_ENTRY_LIST = 10,
|
||||
REQUEST_TRACK_DATA = 11,
|
||||
|
||||
CHANGE_HUD_PAGE = 49,
|
||||
CHANGE_FOCUS = 50,
|
||||
INSTANT_REPLAY_REQUEST = 51,
|
||||
|
||||
PLAY_MANUAL_REPLAY_HIGHLIGHT = 52, // TODO, but planned
|
||||
SAVE_MANUAL_REPLAY_HIGHLIGHT = 60 // TODO, but planned: saving manual replays gives distributed clients the possibility to see the play the same replay
|
||||
}
|
||||
|
||||
public enum InboundMessageTypes : byte
|
||||
{
|
||||
REGISTRATION_RESULT = 1,
|
||||
REALTIME_UPDATE = 2,
|
||||
REALTIME_CAR_UPDATE = 3,
|
||||
ENTRY_LIST = 4,
|
||||
ENTRY_LIST_CAR = 6,
|
||||
TRACK_DATA = 5,
|
||||
BROADCASTING_EVENT = 7
|
||||
}
|
||||
|
||||
public class BroadcastingNetworkProtocol
|
||||
{
|
||||
public const int BROADCASTING_PROTOCOL_VERSION = 4;
|
||||
private string ConnectionIdentifier { get; }
|
||||
private SendMessageDelegate Send { get; }
|
||||
public int ConnectionId { get; private set; }
|
||||
public float TrackMeters { get; private set; }
|
||||
|
||||
internal delegate void SendMessageDelegate(byte[] payload);
|
||||
|
||||
#region Events
|
||||
|
||||
public delegate void ConnectionStateChangedDelegate(int connectionId, bool connectionSuccess, bool isReadonly, string error);
|
||||
public event ConnectionStateChangedDelegate OnConnectionStateChanged;
|
||||
|
||||
public delegate void TrackDataUpdateDelegate(string sender, TrackData trackUpdate);
|
||||
public event TrackDataUpdateDelegate OnTrackDataUpdate;
|
||||
|
||||
public delegate void EntryListUpdateDelegate(string sender, CarInfo car);
|
||||
public event EntryListUpdateDelegate OnEntrylistUpdate;
|
||||
|
||||
public delegate void RealtimeUpdateDelegate(string sender, RealtimeUpdate update);
|
||||
public event RealtimeUpdateDelegate OnRealtimeUpdate;
|
||||
|
||||
public delegate void RealtimeCarUpdateDelegate(string sender, RealtimeCarUpdate carUpdate);
|
||||
public event RealtimeCarUpdateDelegate OnRealtimeCarUpdate;
|
||||
|
||||
public delegate void BroadcastingEventDelegate(string sender, BroadcastingEvent evt);
|
||||
public event BroadcastingEventDelegate OnBroadcastingEvent;
|
||||
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region EntryList handling
|
||||
|
||||
// To avoid huge UDP pakets for longer entry lists, we will first receive the indexes of cars and drivers,
|
||||
// cache the entries and wait for the detailled updates
|
||||
List<CarInfo> _entryListCars = new List<CarInfo>();
|
||||
|
||||
#endregion
|
||||
|
||||
#region optional failsafety - detect when we have a desync and need a new entry list
|
||||
|
||||
DateTime lastEntrylistRequest = DateTime.Now;
|
||||
|
||||
#endregion
|
||||
|
||||
internal BroadcastingNetworkProtocol(string connectionIdentifier, SendMessageDelegate sendMessageDelegate)
|
||||
{
|
||||
if (string.IsNullOrEmpty(connectionIdentifier))
|
||||
throw new ArgumentNullException(nameof(connectionIdentifier), $"No connection identifier set; we use this to distinguish different connections. Using the remote IP:Port is a good idea");
|
||||
|
||||
if (sendMessageDelegate == null)
|
||||
throw new ArgumentNullException(nameof(sendMessageDelegate), $"The protocol class doesn't know anything about the network layer; please put a callback we can use to send data via UDP");
|
||||
|
||||
ConnectionIdentifier = connectionIdentifier;
|
||||
Send = sendMessageDelegate;
|
||||
}
|
||||
|
||||
internal void ProcessMessage(BinaryReader br)
|
||||
{
|
||||
// Any message starts with an 1-byte command type
|
||||
var messageType = (InboundMessageTypes)br.ReadByte();
|
||||
switch (messageType)
|
||||
{
|
||||
case InboundMessageTypes.REGISTRATION_RESULT:
|
||||
{
|
||||
ConnectionId = br.ReadInt32();
|
||||
var connectionSuccess = br.ReadByte() > 0;
|
||||
var isReadonly = br.ReadByte() == 0;
|
||||
var errMsg = ReadString(br);
|
||||
|
||||
OnConnectionStateChanged?.Invoke(ConnectionId, connectionSuccess, isReadonly, errMsg);
|
||||
|
||||
// In case this was successful, we will request the initial data
|
||||
RequestEntryList();
|
||||
RequestTrackData();
|
||||
}
|
||||
break;
|
||||
case InboundMessageTypes.ENTRY_LIST:
|
||||
{
|
||||
_entryListCars.Clear();
|
||||
|
||||
var connectionId = br.ReadInt32();
|
||||
var carEntryCount = br.ReadUInt16();
|
||||
for (int i = 0; i < carEntryCount; i++)
|
||||
{
|
||||
_entryListCars.Add(new CarInfo(br.ReadUInt16()));
|
||||
}
|
||||
}
|
||||
break;
|
||||
case InboundMessageTypes.ENTRY_LIST_CAR:
|
||||
{
|
||||
|
||||
var carId = br.ReadUInt16();
|
||||
|
||||
var carInfo = _entryListCars.SingleOrDefault(x => x.CarIndex == carId);
|
||||
if(carInfo == null)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine($"Entry list update for unknown carIndex {carId}");
|
||||
break;
|
||||
}
|
||||
|
||||
carInfo.CarModelType = br.ReadByte(); // Byte sized car model
|
||||
carInfo.TeamName = ReadString(br);
|
||||
carInfo.RaceNumber = br.ReadInt32();
|
||||
carInfo.CupCategory = br.ReadByte(); // Cup: Overall/Pro = 0, ProAm = 1, Am = 2, Silver = 3, National = 4
|
||||
carInfo.CurrentDriverIndex = br.ReadByte();
|
||||
carInfo.Nationality = (NationalityEnum)br.ReadUInt16();
|
||||
|
||||
// Now the drivers on this car:
|
||||
var driversOnCarCount = br.ReadByte();
|
||||
for (int di = 0; di < driversOnCarCount; di++)
|
||||
{
|
||||
var driverInfo = new DriverInfo();
|
||||
|
||||
driverInfo.FirstName = ReadString(br);
|
||||
driverInfo.LastName = ReadString(br);
|
||||
driverInfo.ShortName = ReadString(br);
|
||||
driverInfo.Category = (DriverCategory)br.ReadByte(); // Platinum = 3, Gold = 2, Silver = 1, Bronze = 0
|
||||
|
||||
// new in 1.13.11:
|
||||
driverInfo.Nationality = (NationalityEnum)br.ReadUInt16();
|
||||
|
||||
carInfo.AddDriver(driverInfo);
|
||||
}
|
||||
|
||||
OnEntrylistUpdate?.Invoke(ConnectionIdentifier, carInfo);
|
||||
}
|
||||
break;
|
||||
case InboundMessageTypes.REALTIME_UPDATE:
|
||||
{
|
||||
RealtimeUpdate update = new RealtimeUpdate();
|
||||
update.EventIndex = (int)br.ReadUInt16();
|
||||
update.SessionIndex = (int)br.ReadUInt16();
|
||||
update.SessionType = (RaceSessionType)br.ReadByte();
|
||||
update.Phase = (SessionPhase)br.ReadByte();
|
||||
var sessionTime = br.ReadSingle();
|
||||
update.SessionTime = TimeSpan.FromMilliseconds(sessionTime);
|
||||
var sessionEndTime = br.ReadSingle();
|
||||
update.SessionEndTime = TimeSpan.FromMilliseconds(sessionEndTime);
|
||||
|
||||
update.FocusedCarIndex = br.ReadInt32();
|
||||
update.ActiveCameraSet = ReadString(br);
|
||||
update.ActiveCamera = ReadString(br);
|
||||
update.CurrentHudPage = ReadString(br);
|
||||
|
||||
update.IsReplayPlaying = br.ReadByte() > 0;
|
||||
if (update.IsReplayPlaying)
|
||||
{
|
||||
update.ReplaySessionTime = br.ReadSingle();
|
||||
update.ReplayRemainingTime = br.ReadSingle();
|
||||
}
|
||||
|
||||
update.TimeOfDay = TimeSpan.FromMilliseconds(br.ReadSingle());
|
||||
update.AmbientTemp = br.ReadByte();
|
||||
update.TrackTemp = br.ReadByte();
|
||||
update.Clouds = br.ReadByte() / 10.0f;
|
||||
update.RainLevel = br.ReadByte() / 10.0f;
|
||||
update.Wetness = br.ReadByte() / 10.0f;
|
||||
|
||||
update.BestSessionLap = ReadLap(br);
|
||||
|
||||
OnRealtimeUpdate?.Invoke(ConnectionIdentifier, update);
|
||||
}
|
||||
break;
|
||||
case InboundMessageTypes.REALTIME_CAR_UPDATE:
|
||||
{
|
||||
RealtimeCarUpdate carUpdate = new RealtimeCarUpdate();
|
||||
|
||||
carUpdate.CarIndex = br.ReadUInt16();
|
||||
carUpdate.DriverIndex = br.ReadUInt16(); // Driver swap will make this change
|
||||
carUpdate.DriverCount = br.ReadByte();
|
||||
carUpdate.Gear = br.ReadByte() - 2; // -2 makes the R -1, N 0 and the rest as-is
|
||||
carUpdate.WorldPosX = br.ReadSingle();
|
||||
carUpdate.WorldPosY = br.ReadSingle();
|
||||
carUpdate.Yaw = br.ReadSingle();
|
||||
carUpdate.CarLocation = (CarLocationEnum)br.ReadByte(); // - , Track, Pitlane, PitEntry, PitExit = 4
|
||||
carUpdate.Kmh = br.ReadUInt16();
|
||||
carUpdate.Position = br.ReadUInt16(); // official P/Q/R position (1 based)
|
||||
carUpdate.CupPosition = br.ReadUInt16(); // official P/Q/R position (1 based)
|
||||
carUpdate.TrackPosition = br.ReadUInt16(); // position on track (1 based)
|
||||
carUpdate.SplinePosition = br.ReadSingle(); // track position between 0.0 and 1.0
|
||||
carUpdate.Laps = br.ReadUInt16();
|
||||
|
||||
carUpdate.Delta = br.ReadInt32(); // Realtime delta to best session lap
|
||||
carUpdate.BestSessionLap = ReadLap(br);
|
||||
carUpdate.LastLap = ReadLap(br);
|
||||
carUpdate.CurrentLap = ReadLap(br);
|
||||
|
||||
// the concept is: "don't know a car or driver? ask for an entry list update"
|
||||
var carEntry = _entryListCars.FirstOrDefault(x => x.CarIndex == carUpdate.CarIndex);
|
||||
if(carEntry == null || carEntry.Drivers.Count != carUpdate.DriverCount)
|
||||
{
|
||||
if ((DateTime.Now - lastEntrylistRequest).TotalSeconds > 1)
|
||||
{
|
||||
lastEntrylistRequest = DateTime.Now;
|
||||
RequestEntryList();
|
||||
System.Diagnostics.Debug.WriteLine($"CarUpdate {carUpdate.CarIndex}|{carUpdate.DriverIndex} not know, will ask for new EntryList");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
OnRealtimeCarUpdate?.Invoke(ConnectionIdentifier, carUpdate);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case InboundMessageTypes.TRACK_DATA:
|
||||
{
|
||||
var connectionId = br.ReadInt32();
|
||||
var trackData = new TrackData();
|
||||
|
||||
trackData.TrackName = ReadString(br);
|
||||
trackData.TrackId = br.ReadInt32();
|
||||
trackData.TrackMeters = br.ReadInt32();
|
||||
TrackMeters = trackData.TrackMeters > 0 ? trackData.TrackMeters : -1;
|
||||
|
||||
trackData.CameraSets = new Dictionary<string, List<string>>();
|
||||
|
||||
var cameraSetCount = br.ReadByte();
|
||||
for (int camSet = 0; camSet < cameraSetCount; camSet++)
|
||||
{
|
||||
var camSetName = ReadString(br);
|
||||
trackData.CameraSets.Add(camSetName, new List<string>());
|
||||
|
||||
var cameraCount = br.ReadByte();
|
||||
for (int cam = 0; cam < cameraCount; cam++)
|
||||
{
|
||||
var cameraName = ReadString(br);
|
||||
trackData.CameraSets[camSetName].Add(cameraName);
|
||||
}
|
||||
}
|
||||
|
||||
var hudPages = new List<string>();
|
||||
var hudPagesCount = br.ReadByte();
|
||||
for (int i = 0; i < hudPagesCount; i++)
|
||||
{
|
||||
hudPages.Add(ReadString(br));
|
||||
}
|
||||
trackData.HUDPages = hudPages;
|
||||
|
||||
OnTrackDataUpdate?.Invoke(ConnectionIdentifier, trackData);
|
||||
}
|
||||
break;
|
||||
case InboundMessageTypes.BROADCASTING_EVENT:
|
||||
{
|
||||
BroadcastingEvent evt = new BroadcastingEvent()
|
||||
{
|
||||
Type = (BroadcastingCarEventType)br.ReadByte(),
|
||||
Msg = ReadString(br),
|
||||
TimeMs = br.ReadInt32(),
|
||||
CarId = br.ReadInt32(),
|
||||
};
|
||||
|
||||
evt.CarData = _entryListCars.FirstOrDefault(x => x.CarIndex == evt.CarId);
|
||||
OnBroadcastingEvent?.Invoke(ConnectionIdentifier, evt);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Laps are always sent in a common way, it makes sense to have a shared function to parse them
|
||||
/// </summary>
|
||||
private static LapInfo ReadLap(BinaryReader br)
|
||||
{
|
||||
var lap = new LapInfo();
|
||||
lap.LaptimeMS = br.ReadInt32();
|
||||
|
||||
lap.CarIndex = br.ReadUInt16();
|
||||
lap.DriverIndex = br.ReadUInt16();
|
||||
|
||||
var splitCount = br.ReadByte();
|
||||
for (int i = 0; i < splitCount; i++)
|
||||
lap.Splits.Add(br.ReadInt32());
|
||||
|
||||
lap.IsInvalid = br.ReadByte() > 0;
|
||||
lap.IsValidForBest = br.ReadByte() > 0;
|
||||
|
||||
var isOutlap = br.ReadByte() > 0;
|
||||
var isInlap = br.ReadByte() > 0;
|
||||
|
||||
if (isOutlap)
|
||||
lap.Type = LapType.Outlap;
|
||||
else if (isInlap)
|
||||
lap.Type = LapType.Inlap;
|
||||
else
|
||||
lap.Type = LapType.Regular;
|
||||
|
||||
// Now it's possible that this is "no" lap that doesn't even include a
|
||||
// first split, we can detect this by comparing with int32.Max
|
||||
while (lap.Splits.Count < 3)
|
||||
{
|
||||
lap.Splits.Add(null);
|
||||
}
|
||||
|
||||
// "null" entries are Int32.Max, in the C# world we can replace this to null
|
||||
for (int i = 0; i < lap.Splits.Count; i++)
|
||||
if (lap.Splits[i] == Int32.MaxValue)
|
||||
lap.Splits[i] = null;
|
||||
|
||||
if (lap.LaptimeMS == Int32.MaxValue)
|
||||
lap.LaptimeMS = null;
|
||||
|
||||
return lap;
|
||||
}
|
||||
|
||||
private static string ReadString(BinaryReader br)
|
||||
{
|
||||
var length = br.ReadUInt16();
|
||||
var bytes = br.ReadBytes(length);
|
||||
return Encoding.UTF8.GetString(bytes);
|
||||
}
|
||||
|
||||
private static void WriteString(BinaryWriter bw, string s)
|
||||
{
|
||||
var bytes = Encoding.UTF8.GetBytes(s);
|
||||
bw.Write(Convert.ToUInt16(bytes.Length));
|
||||
bw.Write(bytes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Will try to register this client in the targeted ACC instance.
|
||||
/// Needs to be called once, before anything else can happen.
|
||||
/// </summary>
|
||||
/// <param name="connectionPassword"></param>
|
||||
/// <param name="msRealtimeUpdateInterval"></param>
|
||||
/// <param name="commandPassword"></param>
|
||||
internal void RequestConnection(string displayName, string connectionPassword, int msRealtimeUpdateInterval, string commandPassword)
|
||||
{
|
||||
using (var ms = new MemoryStream())
|
||||
using (var br = new BinaryWriter(ms))
|
||||
{
|
||||
br.Write((byte)OutboundMessageTypes.REGISTER_COMMAND_APPLICATION); // First byte is always the command type
|
||||
br.Write((byte)BROADCASTING_PROTOCOL_VERSION);
|
||||
|
||||
WriteString(br, displayName);
|
||||
WriteString(br, connectionPassword);
|
||||
br.Write(msRealtimeUpdateInterval);
|
||||
WriteString(br, commandPassword);
|
||||
|
||||
Send(ms.ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
internal void Disconnect()
|
||||
{
|
||||
using (var ms = new MemoryStream())
|
||||
using (var br = new BinaryWriter(ms))
|
||||
{
|
||||
br.Write((byte)OutboundMessageTypes.UNREGISTER_COMMAND_APPLICATION); // First byte is always the command type
|
||||
Send(ms.ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Will ask the ACC client for an updated entry list, containing all car and driver data.
|
||||
/// The client will send this automatically when something changes; however if you detect a carIndex or driverIndex, this may cure the
|
||||
/// problem for future updates
|
||||
/// </summary>
|
||||
private void RequestEntryList()
|
||||
{
|
||||
using (var ms = new MemoryStream())
|
||||
using (var br = new BinaryWriter(ms))
|
||||
{
|
||||
br.Write((byte)OutboundMessageTypes.REQUEST_ENTRY_LIST); // First byte is always the command type
|
||||
br.Write((int)ConnectionId);
|
||||
|
||||
Send(ms.ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
private void RequestTrackData()
|
||||
{
|
||||
using (var ms = new MemoryStream())
|
||||
using (var br = new BinaryWriter(ms))
|
||||
{
|
||||
br.Write((byte)OutboundMessageTypes.REQUEST_TRACK_DATA); // First byte is always the command type
|
||||
br.Write((int)ConnectionId);
|
||||
|
||||
Send(ms.ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
public void SetFocus(UInt16 carIndex)
|
||||
{
|
||||
SetFocusInternal(carIndex, null, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Always put both cam + cam set; even if it doesn't make sense
|
||||
/// </summary>
|
||||
public void SetCamera(string cameraSet, string camera)
|
||||
{
|
||||
SetFocusInternal(null, cameraSet, camera);
|
||||
}
|
||||
|
||||
public void SetFocus(UInt16 carIndex, string cameraSet, string camera)
|
||||
{
|
||||
SetFocusInternal(carIndex, cameraSet, camera);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends the request to change the focused car and/or the camera used.
|
||||
/// The idea is that this often wants to be triggered together, so this is a all-in-one function.
|
||||
/// This way we can make sure the switch happens in the same frame, even in more complex scenarios
|
||||
/// </summary>
|
||||
private void SetFocusInternal(UInt16? carIndex, string cameraSet, string camera)
|
||||
{
|
||||
using (var ms = new MemoryStream())
|
||||
using (var bw = new BinaryWriter(ms))
|
||||
{
|
||||
bw.Write((byte)OutboundMessageTypes.CHANGE_FOCUS); // First byte is always the command type
|
||||
bw.Write((int)ConnectionId);
|
||||
|
||||
if (!carIndex.HasValue)
|
||||
{
|
||||
bw.Write((byte)0); // No change of focused car
|
||||
}
|
||||
else
|
||||
{
|
||||
bw.Write((byte)1);
|
||||
bw.Write((UInt16)(carIndex.Value));
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(cameraSet) || string.IsNullOrEmpty(camera))
|
||||
{
|
||||
bw.Write((byte)0); // No change of camera set or camera
|
||||
}
|
||||
else
|
||||
{
|
||||
bw.Write((byte)1);
|
||||
WriteString(bw, cameraSet);
|
||||
WriteString(bw, camera);
|
||||
}
|
||||
|
||||
Send(ms.ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
public void RequestInstantReplay(float startSessionTime, float durationMS, int initialFocusedCarIndex = -1, string initialCameraSet = "", string initialCamera = "")
|
||||
{
|
||||
using (var ms = new MemoryStream())
|
||||
using (var bw = new BinaryWriter(ms))
|
||||
{
|
||||
bw.Write((byte)OutboundMessageTypes.INSTANT_REPLAY_REQUEST); // First byte is always the command type
|
||||
bw.Write((int)ConnectionId);
|
||||
|
||||
bw.Write((float)startSessionTime);
|
||||
bw.Write((float)durationMS);
|
||||
bw.Write((int)initialFocusedCarIndex);
|
||||
|
||||
WriteString(bw, initialCameraSet);
|
||||
WriteString(bw, initialCamera);
|
||||
|
||||
Send(ms.ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
public void RequestHUDPage(string hudPage)
|
||||
{
|
||||
using (var ms = new MemoryStream())
|
||||
using (var bw = new BinaryWriter(ms))
|
||||
{
|
||||
bw.Write((byte)OutboundMessageTypes.CHANGE_HUD_PAGE); // First byte is always the command type
|
||||
bw.Write((int)ConnectionId);
|
||||
|
||||
WriteString(bw, hudPage);
|
||||
|
||||
Send(ms.ToArray());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,36 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("ksBroadcastingNetwork")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("ksBroadcastingNetwork")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2018")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("1ef9a746-3771-4052-b61b-04bdb3dc381a")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
@@ -0,0 +1,17 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace ksBroadcastingNetwork.Structs
|
||||
{
|
||||
public struct BroadcastingEvent
|
||||
{
|
||||
public BroadcastingCarEventType Type { get; internal set; }
|
||||
public string Msg { get; internal set; }
|
||||
public int TimeMs { get; internal set; }
|
||||
public int CarId { get; internal set; }
|
||||
public CarInfo CarData { get; internal set; }
|
||||
}
|
||||
}
|
@@ -0,0 +1,37 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace ksBroadcastingNetwork.Structs
|
||||
{
|
||||
public class CarInfo
|
||||
{
|
||||
public ushort CarIndex { get; }
|
||||
public byte CarModelType { get; internal set; }
|
||||
public string TeamName { get; internal set; }
|
||||
public int RaceNumber { get; internal set; }
|
||||
public byte CupCategory { get; internal set; }
|
||||
public int CurrentDriverIndex { get; internal set; }
|
||||
public IList<DriverInfo> Drivers { get; } = new List<DriverInfo>();
|
||||
public NationalityEnum Nationality { get; internal set; }
|
||||
|
||||
public CarInfo(ushort carIndex)
|
||||
{
|
||||
CarIndex = carIndex;
|
||||
}
|
||||
|
||||
internal void AddDriver(DriverInfo driverInfo)
|
||||
{
|
||||
Drivers.Add(driverInfo);
|
||||
}
|
||||
|
||||
public string GetCurrentDriverName()
|
||||
{
|
||||
if (CurrentDriverIndex < Drivers.Count)
|
||||
return Drivers[CurrentDriverIndex].LastName;
|
||||
return "nobody(?)";
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,17 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace ksBroadcastingNetwork.Structs
|
||||
{
|
||||
public struct DriverInfo
|
||||
{
|
||||
public string FirstName { get; internal set; }
|
||||
public string LastName { get; internal set; }
|
||||
public string ShortName { get; internal set; }
|
||||
public DriverCategory Category { get; internal set; }
|
||||
public NationalityEnum Nationality { get; internal set; }
|
||||
}
|
||||
}
|
@@ -0,0 +1,24 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace ksBroadcastingNetwork.Structs
|
||||
{
|
||||
public class LapInfo
|
||||
{
|
||||
public int? LaptimeMS { get; internal set; }
|
||||
public List<int?> Splits { get; } = new List<int?>();
|
||||
public ushort CarIndex { get; internal set; }
|
||||
public ushort DriverIndex { get; internal set; }
|
||||
public bool IsInvalid { get; internal set; }
|
||||
public bool IsValidForBest { get; internal set; }
|
||||
public LapType Type { get; internal set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{LaptimeMS, 5}|{string.Join("|", Splits)}";
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,30 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace ksBroadcastingNetwork.Structs
|
||||
{
|
||||
public struct RealtimeCarUpdate
|
||||
{
|
||||
public int CarIndex { get; internal set; }
|
||||
public int DriverIndex { get; internal set; }
|
||||
public int Gear { get; internal set; }
|
||||
public float WorldPosX { get; internal set; }
|
||||
public float WorldPosY { get; internal set; }
|
||||
public float Yaw { get; internal set; }
|
||||
public CarLocationEnum CarLocation { get; internal set; }
|
||||
public int Kmh { get; internal set; }
|
||||
public int Position { get; internal set; }
|
||||
public int TrackPosition { get; internal set; }
|
||||
public float SplinePosition { get; internal set; }
|
||||
public int Delta { get; internal set; }
|
||||
public LapInfo BestSessionLap { get; internal set; }
|
||||
public LapInfo LastLap { get; internal set; }
|
||||
public LapInfo CurrentLap { get; internal set; }
|
||||
public int Laps { get; internal set; }
|
||||
public ushort CupPosition { get; internal set; }
|
||||
public byte DriverCount { get; internal set; }
|
||||
}
|
||||
}
|
@@ -0,0 +1,36 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace ksBroadcastingNetwork.Structs
|
||||
{
|
||||
public struct RealtimeUpdate
|
||||
{
|
||||
public int EventIndex { get; internal set; }
|
||||
public int SessionIndex { get; internal set; }
|
||||
public SessionPhase Phase { get; internal set; }
|
||||
public TimeSpan SessionTime { get; internal set; }
|
||||
public TimeSpan RemainingTime { get; internal set; }
|
||||
public TimeSpan TimeOfDay { get; internal set; }
|
||||
public float RainLevel { get; internal set; }
|
||||
public float Clouds { get; internal set; }
|
||||
public float Wetness { get; internal set; }
|
||||
public LapInfo BestSessionLap { get; internal set; }
|
||||
public ushort BestLapCarIndex { get; internal set; }
|
||||
public ushort BestLapDriverIndex { get; internal set; }
|
||||
public int FocusedCarIndex { get; internal set; }
|
||||
public string ActiveCameraSet { get; internal set; }
|
||||
public string ActiveCamera { get; internal set; }
|
||||
public bool IsReplayPlaying { get; internal set; }
|
||||
public float ReplaySessionTime { get; internal set; }
|
||||
public float ReplayRemainingTime { get; internal set; }
|
||||
public TimeSpan SessionRemainingTime { get; internal set; }
|
||||
public TimeSpan SessionEndTime { get; internal set; }
|
||||
public RaceSessionType SessionType { get; internal set; }
|
||||
public byte AmbientTemp { get; internal set; }
|
||||
public byte TrackTemp { get; internal set; }
|
||||
public string CurrentHudPage { get; internal set; }
|
||||
}
|
||||
}
|
@@ -0,0 +1,17 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace ksBroadcastingNetwork.Structs
|
||||
{
|
||||
public struct TrackData
|
||||
{
|
||||
public string TrackName { get; internal set; }
|
||||
public int TrackId { get; internal set; }
|
||||
public float TrackMeters { get; internal set; }
|
||||
public Dictionary<string, List<string>> CameraSets { get; internal set; }
|
||||
public IEnumerable<string> HUDPages { get; internal set; }
|
||||
}
|
||||
}
|
@@ -0,0 +1,57 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{1EF9A746-3771-4052-B61B-04BDB3DC381A}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>ksBroadcastingNetwork</RootNamespace>
|
||||
<AssemblyName>ksBroadcastingNetwork</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<Deterministic>true</Deterministic>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="ACCUdpRemoteClient.cs" />
|
||||
<Compile Include="BroadcastingEnums.cs" />
|
||||
<Compile Include="BroadcastingNetworkProtocol.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Structs\BroadcastingEvent.cs" />
|
||||
<Compile Include="Structs\CarInfo.cs" />
|
||||
<Compile Include="Structs\DriverInfo.cs" />
|
||||
<Compile Include="Structs\LapInfo.cs" />
|
||||
<Compile Include="Structs\RealtimeCarUpdate.cs" />
|
||||
<Compile Include="Structs\RealtimeUpdate.cs" />
|
||||
<Compile Include="Structs\TrackData.cs" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
102
acc-web/accserver/sdk/broadcasting/Sources/ksBroadcastingNetwork/server.log
Executable file
102
acc-web/accserver/sdk/broadcasting/Sources/ksBroadcastingNetwork/server.log
Executable file
@@ -0,0 +1,102 @@
|
||||
Server Log Start
|
||||
Server Version 212
|
||||
SessionStateChange: 1 start: 40.000000 end: 5000.000000
|
||||
Sent Lobby Registration Request with trackName hungaroring
|
||||
RegisterToLobby succeeded
|
||||
WARNING: Lobby accepted connection
|
||||
Sent config to kson
|
||||
Sent connected drivers list to kson
|
||||
SessionStateChange: 4 start: 5002.000000 end: 5002.000000
|
||||
Sent new session state to kson
|
||||
SessionStateChange: 5 start: 5008.000000 end: 1805008.000000
|
||||
Sent new session state to kson
|
||||
SessionStateChange: 6 start: 5008.000000 end: 1820009.000000
|
||||
Sent new session state to kson
|
||||
SessionStateChange: 7 start: 5008.000000 end: 1830012.000000
|
||||
Sent new session state to kson
|
||||
SessionStateChange: 8 start: 5008.000000 end: 1845015.000000
|
||||
Sent new session state to kson
|
||||
SessionOverUpdate currentSessionIndex: 1 currentEventIndex: 0
|
||||
SessionStateChange: 1 start: 1845063.000000 end: 5000.000000
|
||||
Sent new session state to kson
|
||||
SessionStateChange: 4 start: 5003.000000 end: 5003.000000
|
||||
Sent new session state to kson
|
||||
SessionStateChange: 5 start: 5010.000000 end: 3605010.000000
|
||||
Sent new session state to kson
|
||||
New connection received 336
|
||||
TCP PACKET received with ID:9
|
||||
ACP_REQUEST_CONNECTION
|
||||
CLIENT VERSION: 212
|
||||
addNewConnectedCar: new car connected, adding it to the list of connected cars
|
||||
Found and added a new player
|
||||
New Connection created, new connectedCarId: 1 new connectionId: 1
|
||||
Sent connected drivers list to kson
|
||||
SessionStateChange: 1 start: 2473227.000000 end: 5000.000000
|
||||
Sent new session state to kson
|
||||
UDP Packet id: 19
|
||||
TCP PACKET received with ID:44
|
||||
TCP PACKET received with ID:44
|
||||
TCP PACKET received with ID:41
|
||||
TCP PACKET received with ID:45
|
||||
TCP PACKET received with ID:48
|
||||
SessionStateChange: 4 start: 5005.000000 end: 5005.000000
|
||||
Sent new session state to kson
|
||||
SessionStateChange: 5 start: 5012.000000 end: 1805012.000000
|
||||
Sent new session state to kson
|
||||
TCP PACKET received with ID:50
|
||||
ACP_CAR_LOCATION_UPDATE location updated for carIndex 0
|
||||
TCP PACKET received with ID:50
|
||||
ACP_CAR_LOCATION_UPDATE location updated for carIndex 0
|
||||
TCP PACKET received with ID:49
|
||||
ACP_RACE_MANAGER_INFO_COMPLETED connectionId 1 is ready to reaceive packets
|
||||
TCP PACKET received with ID:50
|
||||
ACP_CAR_LOCATION_UPDATE location updated for carIndex 0
|
||||
TCP PACKET received with ID:50
|
||||
ACP_CAR_LOCATION_UPDATE location updated for carIndex 0
|
||||
TCP PACKET received with ID:50
|
||||
ACP_CAR_LOCATION_UPDATE location updated for carIndex 0
|
||||
New connection received 344
|
||||
TCP PACKET received with ID:9
|
||||
ACP_REQUEST_CONNECTION
|
||||
CLIENT VERSION: 212
|
||||
addNewConnectedCar: new car connected, adding it to the list of connected cars
|
||||
Found and added a new player
|
||||
New Connection created, new connectedCarId: 2 new connectionId: 2
|
||||
Sent connected drivers list to kson
|
||||
UDP Packet id: 19
|
||||
TCP PACKET received with ID:44
|
||||
TCP PACKET received with ID:44
|
||||
TCP PACKET received with ID:41
|
||||
TCP PACKET received with ID:45
|
||||
TCP PACKET received with ID:48
|
||||
TCP PACKET received with ID:49
|
||||
ACP_RACE_MANAGER_INFO_COMPLETED connectionId 2 is ready to reaceive packets
|
||||
TCP PACKET received with ID:34
|
||||
CAR_INFO_REQUEST for ID: 2
|
||||
Car Info Response sent idRequested: 2, carIndex: 1, driverIndex: 1
|
||||
TCP PACKET received with ID:50
|
||||
ACP_CAR_LOCATION_UPDATE location updated for carIndex 1
|
||||
TCP PACKET received with ID:50
|
||||
ACP_CAR_LOCATION_UPDATE location updated for carIndex 1
|
||||
TCP PACKET received with ID:34
|
||||
CAR_INFO_REQUEST for ID: 1
|
||||
Car Info Response sent idRequested: 1, carIndex: 0, driverIndex: 0
|
||||
TCP PACKET received with ID:50
|
||||
ACP_CAR_LOCATION_UPDATE location updated for carIndex 1
|
||||
TCP PACKET received with ID:33
|
||||
TCP PACKET received with ID:50
|
||||
ACP_CAR_LOCATION_UPDATE location updated for carIndex 1
|
||||
TCP PACKET received with ID:50
|
||||
ACP_CAR_LOCATION_UPDATE location updated for carIndex 1
|
||||
TCP PACKET received with ID:33
|
||||
TCP PACKET received with ID:50
|
||||
ACP_CAR_LOCATION_UPDATE location updated for carIndex 1
|
||||
TCP PACKET received with ID:50
|
||||
ACP_CAR_LOCATION_UPDATE location updated for carIndex 0
|
||||
TCP PACKET received with ID:50
|
||||
ACP_CAR_LOCATION_UPDATE location updated for carIndex 0
|
||||
TCP PACKET received with ID:50
|
||||
ACP_CAR_LOCATION_UPDATE location updated for carIndex 0
|
||||
TCP PACKET received with ID:33
|
||||
TCP PACKET received with ID:50
|
||||
ACP_CAR_LOCATION_UPDATE
|
Reference in New Issue
Block a user