Skip to content

Commit 9ea53a1

Browse files
committed
Merge branch 'hotfix/2796-va-variables' into develop
2 parents 4786d87 + b1ecb33 commit 9ea53a1

27 files changed

Lines changed: 1231 additions & 588 deletions

ChangeLog.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,17 @@
22

33
Full details of the variables available for each noted event, and VoiceAttack integrations, are available in the individual [event pages](https://github.com/EDCD/EDDI/wiki/Events).
44

5+
## 5.0.1
6+
* Core
7+
* Fixed generated consolidated organic names for Horizons organics.
8+
* Speech Responder
9+
* Fixed vertical whitespace characters being removed from speechresponder.out. (#2797)
10+
* Custom Functions
11+
* `StopSpeaking` function signature corrected - it should now work as documented. (#2799)
12+
* VoiceAttack
13+
* Fix dropping variables "set" before VoiceAttack initialization is completed (#2796).
14+
* Optimized the way that EDDI sends variables to VoiceAttack to improve performance and reliability (#2798).
15+
516
## 5.0.0
617
* Core
718
* Added support for the Lynx Highliner and associated new modules.

DataDefinitions/Organic.cs

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using JetBrains.Annotations;
22
using Newtonsoft.Json;
3+
using System;
34
using System.Linq;
45

56
namespace EddiDataDefinitions
@@ -35,10 +36,10 @@ public OrganicVariant variant
3536
private OrganicVariant _variant;
3637

3738
[ Utilities.PublicAPI("The invariant name of the organic")]
38-
public string invariantName => ConsolidatedName( _variant?.invariantName, _species?.invariantName, genus?.invariantName );
39+
public string invariantName => ConsolidatedName( genus?.organicGroup, _variant?.invariantName, _species?.invariantName, genus?.invariantName );
3940

4041
[Utilities.PublicAPI("The localized name of the organic")]
41-
public string localizedName => ConsolidatedName( _variant?.localizedName, _species?.localizedName, genus?.localizedName );
42+
public string localizedName => ConsolidatedName( genus?.organicGroup, _variant?.localizedName, _species?.localizedName, genus?.localizedName );
4243

4344
[Utilities.PublicAPI( "The minimum distance that you must travel before you can collect a fresh sample of this genus (if known)" ), JsonIgnore]
4445
public int? minimumDistanceMeters => genus?.minimumDistanceMeters;
@@ -91,15 +92,27 @@ public Organic ( [NotNull] OrganicGenus genus )
9192
/// <summary>
9293
/// Creates a joined organism name without redundant elements
9394
/// </summary>
94-
private string ConsolidatedName ( string variantName, string speciesName, string genusName )
95+
private string ConsolidatedName ( OrganicGenus.OrganicGroup? organicGroup, string variantName,
96+
string speciesName, string genusName )
9597
{
96-
return string.Join( " ", new[]
98+
if ( organicGroup is OrganicGenus.OrganicGroup.Horizons )
99+
{
100+
return string.Join( " ", new[]
97101
{
98102
variantName,
99-
genus != null && speciesName.Contains( genusName ) ? null : genusName,
100-
_species != null && variantName.Contains( speciesName ) ? null : speciesName
103+
_species != null && variantName.Contains( speciesName, StringComparison.OrdinalIgnoreCase ) ? null : speciesName,
104+
genus != null && speciesName.Contains( genusName, StringComparison.OrdinalIgnoreCase ) ? null : genusName
101105
}
102106
.Where( n => n != null ) );
107+
}
108+
109+
return string.Join( " ", new[]
110+
{
111+
variantName,
112+
genus != null && speciesName.Contains( genusName, StringComparison.OrdinalIgnoreCase ) ? null : genusName,
113+
_species != null && variantName.Contains( speciesName, StringComparison.OrdinalIgnoreCase ) ? null : speciesName
114+
}
115+
.Where( n => n != null ) );
103116
}
104117

105118
/// <summary> Get all the biological data, this should be done at the first sample </summary>

DataDefinitions/OrganicGenus.cs

Lines changed: 33 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@ namespace EddiDataDefinitions
55
{
66
public class OrganicGenus : ResourceBasedLocalizedEDName<OrganicGenus>
77
{
8+
public enum OrganicGroup
9+
{
10+
Horizons,
11+
Odyssey
12+
}
13+
814
static OrganicGenus ()
915
{
1016
resourceManager = Properties.OrganicGenus.ResourceManager;
@@ -16,27 +22,27 @@ static OrganicGenus ()
1622
public static readonly OrganicGenus Unknown = new( "Unknown" );
1723

1824
// Terrestrial Genuses
19-
public static readonly OrganicGenus Aleoids = new( "Aleoids", 150 );
20-
public static readonly OrganicGenus Vents = new( "Vents", 100 );
21-
public static readonly OrganicGenus Sphere = new( "Sphere", 100 );
22-
public static readonly OrganicGenus Bacterial = new( "Bacterial", 500 );
23-
public static readonly OrganicGenus Cone = new( "Cone", 100 );
24-
public static readonly OrganicGenus Brancae = new( "Brancae", 100 );
25-
public static readonly OrganicGenus Cactoid = new( "Cactoid", 300 );
26-
public static readonly OrganicGenus Clypeus = new( "Clypeus", 150 );
27-
public static readonly OrganicGenus Conchas = new( "Conchas", 150 );
28-
public static readonly OrganicGenus Ground_Struct_Ice = new( "Ground_Struct_Ice", 100 );
29-
public static readonly OrganicGenus Electricae = new( "Electricae", 1000 );
30-
public static readonly OrganicGenus Fonticulus = new( "Fonticulus", 500 );
31-
public static readonly OrganicGenus Shrubs = new( "Shrubs", 150 );
32-
public static readonly OrganicGenus Fumerolas = new( "Fumerolas", 100 );
33-
public static readonly OrganicGenus Fungoids = new( "Fungoids", 300 );
34-
public static readonly OrganicGenus Osseus = new( "Osseus", 800 );
35-
public static readonly OrganicGenus Recepta = new( "Recepta", 150 );
36-
public static readonly OrganicGenus Tubers = new( "Tubers", 100 );
37-
public static readonly OrganicGenus Stratum = new( "Stratum", 500 );
38-
public static readonly OrganicGenus Tubus = new( "Tubus", 800 );
39-
public static readonly OrganicGenus Tussocks = new( "Tussocks", 200 );
25+
public static readonly OrganicGenus Aleoids = new( "Aleoids", OrganicGroup.Odyssey, minimumDistanceMeters: 150 );
26+
public static readonly OrganicGenus Vents = new( "Vents", OrganicGroup.Odyssey, minimumDistanceMeters: 100 );
27+
public static readonly OrganicGenus Sphere = new( "Sphere", minimumDistanceMeters: 100 );
28+
public static readonly OrganicGenus Bacterial = new( "Bacterial", OrganicGroup.Odyssey, minimumDistanceMeters: 500 );
29+
public static readonly OrganicGenus Cone = new( "Cone", minimumDistanceMeters: 100 );
30+
public static readonly OrganicGenus Brancae = new( "Brancae", OrganicGroup.Odyssey, minimumDistanceMeters: 100 );
31+
public static readonly OrganicGenus Cactoid = new( "Cactoid", OrganicGroup.Odyssey, minimumDistanceMeters: 300 );
32+
public static readonly OrganicGenus Clypeus = new( "Clypeus", OrganicGroup.Odyssey, minimumDistanceMeters: 150 );
33+
public static readonly OrganicGenus Conchas = new( "Conchas", OrganicGroup.Odyssey, minimumDistanceMeters: 150 );
34+
public static readonly OrganicGenus Ground_Struct_Ice = new( "Ground_Struct_Ice", minimumDistanceMeters: 100 );
35+
public static readonly OrganicGenus Electricae = new( "Electricae", OrganicGroup.Odyssey, minimumDistanceMeters: 1000 );
36+
public static readonly OrganicGenus Fonticulus = new( "Fonticulus", OrganicGroup.Odyssey, minimumDistanceMeters: 500 );
37+
public static readonly OrganicGenus Shrubs = new( "Shrubs", OrganicGroup.Odyssey, minimumDistanceMeters: 150 );
38+
public static readonly OrganicGenus Fumerolas = new( "Fumerolas", OrganicGroup.Odyssey, minimumDistanceMeters: 100 );
39+
public static readonly OrganicGenus Fungoids = new( "Fungoids", OrganicGroup.Odyssey, minimumDistanceMeters: 300 );
40+
public static readonly OrganicGenus Osseus = new( "Osseus", OrganicGroup.Odyssey, minimumDistanceMeters: 800 );
41+
public static readonly OrganicGenus Recepta = new( "Recepta", OrganicGroup.Odyssey, minimumDistanceMeters: 150 );
42+
public static readonly OrganicGenus Tubers = new( "Tubers", OrganicGroup.Odyssey, minimumDistanceMeters: 100 );
43+
public static readonly OrganicGenus Stratum = new( "Stratum", OrganicGroup.Odyssey, minimumDistanceMeters: 500 );
44+
public static readonly OrganicGenus Tubus = new( "Tubus", OrganicGroup.Odyssey, minimumDistanceMeters: 800 );
45+
public static readonly OrganicGenus Tussocks = new( "Tussocks", OrganicGroup.Odyssey, minimumDistanceMeters: 200 );
4046
// Genuses without any known minimum distance (including non-terrestrial genuses)
4147
public static readonly OrganicGenus MineralSpheres = new( "MineralSpheres" );
4248
public static readonly OrganicGenus MetallicCrystals = new( "MetallicCrystals" );
@@ -69,21 +75,25 @@ static OrganicGenus ()
6975
public static readonly OrganicGenus VoidHeart = new( "VoidHeart" );
7076
public static readonly OrganicGenus CalcitePlates = new( "CalcitePlates" );
7177
public static readonly OrganicGenus ThargoidBarnacle = new( "ThargoidBarnacle" );
72-
public static readonly OrganicGenus Ingensradices = new( "Ingensradices" ); // Appears to be unique to HIP 87621.
78+
public static readonly OrganicGenus Ingensradices = new( "Ingensradices", OrganicGroup.Odyssey ); // Appears to be unique to HIP 87621.
7379

7480
[JsonProperty]
7581
public int minimumDistanceMeters { get; private set; }
7682

7783
[JsonIgnore, PublicAPI]
7884
public string localizedDescription => Properties.OrganicGenusDesc.ResourceManager.GetString( NormalizeGenus( edname ) );
85+
86+
public OrganicGroup organicGroup { get; private set; }
7987

8088
// dummy used to ensure that the static constructor has run
8189
public OrganicGenus () : this( "" )
8290
{ }
8391

84-
private OrganicGenus ( string edname, int minimumDistanceMeters = 0 ) : base( edname, edname )
92+
private OrganicGenus ( string edname, OrganicGroup organicGroup = OrganicGroup.Horizons,
93+
int minimumDistanceMeters = 0 ) : base( edname, edname )
8594
{
8695
this.minimumDistanceMeters = minimumDistanceMeters;
96+
this.organicGroup = organicGroup;
8797
}
8898

8999
public static new OrganicGenus FromEDName ( string edname )

IPC_Service/Client/IPCClient.cs

Lines changed: 94 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@
1010
using System.IO;
1111
using System.Linq;
1212
using System.Net.Sockets;
13-
using System.Runtime.InteropServices;
14-
using System.Text;
1513
using System.Threading;
1614
using System.Threading.Tasks;
1715

@@ -292,12 +290,15 @@ private async Task SendConnectMessageAsync ()
292290
byte[]? rentedBuffer = null;
293291
try
294292
{
295-
rentedBuffer = ArrayPool<byte>.Shared.Rent( serialized.Length * 2 );
296-
var bytesWritten = Encoding.UTF8.GetBytes( serialized, 0, serialized.Length, rentedBuffer, 0 );
293+
var frame = MessageSerializer.SerializeToFrame( envelope );
297294

298-
// Write data (includes length prefix and JSON)
299-
await _networkStream.WriteAsync( rentedBuffer.AsMemory( 0, bytesWritten ), cancellationToken ).ConfigureAwait( false );
300-
await _networkStream.FlushAsync( cancellationToken ).ConfigureAwait( false );
295+
await _networkStream
296+
.WriteAsync( frame.Memory, cancellationToken )
297+
.ConfigureAwait( false );
298+
299+
await _networkStream
300+
.FlushAsync( cancellationToken )
301+
.ConfigureAwait( false );
301302

302303
_messagesSent++;
303304
_lastActivityAt = DateTime.UtcNow;
@@ -324,38 +325,55 @@ private async Task ReceiveLoopAsync ( CancellationToken cancellationToken )
324325
return;
325326
}
326327

327-
var rentedBuffer = ArrayPool<byte>.Shared.Rent( 4096 );
328-
var bufferedBytes = new List<byte>( 8192 ); // Pre-allocate with typical message capacity
328+
var readBuffer = ArrayPool<byte>.Shared.Rent( 4096 );
329+
var pendingBuffer = ArrayPool<byte>.Shared.Rent( 8192 );
330+
331+
var pendingStart = 0;
332+
var pendingLength = 0;
333+
329334
try
330335
{
331336
while ( !cancellationToken.IsCancellationRequested && ( _tcpClient?.Connected ?? false ) )
332337
{
333338
try
334339
{
335340
var bytesRead = await _networkStream
336-
.ReadAsync( rentedBuffer.AsMemory( 0, 4096 ), cancellationToken )
337-
.ConfigureAwait( false );
341+
.ReadAsync( readBuffer.AsMemory( 0, 4096 ), cancellationToken )
342+
.ConfigureAwait( false );
338343

339344
if ( bytesRead == 0 )
340345
{
341-
// Connection closed by server
342346
break;
343347
}
344348

345-
// More efficient: directly extend the list instead of ToArray() + AddRange()
346-
bufferedBytes.AddRange( rentedBuffer.AsSpan( 0, bytesRead ) );
349+
pendingBuffer = AppendPendingBytes(
350+
pendingBuffer,
351+
ref pendingStart,
352+
ref pendingLength,
353+
readBuffer,
354+
bytesRead );
347355

348-
while ( bufferedBytes.Count > 0 )
356+
while ( pendingLength > 0 )
349357
{
350358
var messageCount = MessageSerializer.DeserializeMessages(
351-
CollectionsMarshal.AsSpan( bufferedBytes ), out var messages, out var bytesConsumed );
359+
pendingBuffer,
360+
pendingStart,
361+
pendingLength,
362+
out var messages,
363+
out var bytesConsumed );
352364

353365
if ( bytesConsumed == 0 )
354366
{
355367
break;
356368
}
357369

358-
bufferedBytes.RemoveRange( 0, bytesConsumed );
370+
pendingStart += bytesConsumed;
371+
pendingLength -= bytesConsumed;
372+
373+
if ( pendingLength == 0 )
374+
{
375+
pendingStart = 0;
376+
}
359377

360378
if ( messageCount == 0 )
361379
{
@@ -374,19 +392,76 @@ private async Task ReceiveLoopAsync ( CancellationToken cancellationToken )
374392
}
375393
catch ( IOException )
376394
{
377-
// Connection lost
378395
break;
379396
}
380397
}
381398
}
382399
finally
383400
{
384-
ArrayPool<byte>.Shared.Return( rentedBuffer );
401+
ArrayPool<byte>.Shared.Return( readBuffer );
402+
ArrayPool<byte>.Shared.Return( pendingBuffer );
403+
385404
IsConnected = false;
386405
ConnectionLost?.Invoke( this, new ConnectionLostEventArgs( "Receive loop ended" ) );
387406
}
388407
}
389408

409+
private static byte[] AppendPendingBytes (
410+
byte[] pendingBuffer,
411+
ref int pendingStart,
412+
ref int pendingLength,
413+
byte[] sourceBuffer,
414+
int sourceLength )
415+
{
416+
var requiredLength = pendingLength + sourceLength;
417+
418+
if ( requiredLength > pendingBuffer.Length )
419+
{
420+
var newSize = Math.Max( requiredLength, pendingBuffer.Length * 2 );
421+
var newBuffer = ArrayPool<byte>.Shared.Rent( newSize );
422+
423+
if ( pendingLength > 0 )
424+
{
425+
Buffer.BlockCopy(
426+
pendingBuffer,
427+
pendingStart,
428+
newBuffer,
429+
0,
430+
pendingLength );
431+
}
432+
433+
ArrayPool<byte>.Shared.Return( pendingBuffer );
434+
435+
pendingBuffer = newBuffer;
436+
pendingStart = 0;
437+
}
438+
else if ( (pendingStart + pendingLength + sourceLength) > pendingBuffer.Length )
439+
{
440+
if ( pendingLength > 0 )
441+
{
442+
Buffer.BlockCopy(
443+
pendingBuffer,
444+
pendingStart,
445+
pendingBuffer,
446+
0,
447+
pendingLength );
448+
}
449+
450+
pendingStart = 0;
451+
}
452+
453+
Buffer.BlockCopy(
454+
sourceBuffer,
455+
0,
456+
pendingBuffer,
457+
pendingStart + pendingLength,
458+
sourceLength );
459+
460+
pendingLength += sourceLength;
461+
462+
return pendingBuffer;
463+
}
464+
390465
private void ProcessReceivedMessage ( MessageEnvelope envelope )
391466
{
392467
_messagesReceived++;

0 commit comments

Comments
 (0)