8
8
using System . Text . RegularExpressions ;
9
9
using System . Threading . Tasks ;
10
10
using Nito . AsyncEx ;
11
+ using System . Collections . Concurrent ;
12
+ using System . Diagnostics . Contracts ;
11
13
12
14
namespace Guncho
13
15
{
@@ -806,10 +808,9 @@ private bool AllowSetPlayerAttribute(string name, string value)
806
808
private class RealmIO
807
809
{
808
810
private readonly Instance instance ;
809
- private readonly Queue < string > inputQueue = new Queue < string > ( ) ;
810
- private readonly Queue < Transaction > transQueue = new Queue < Transaction > ( ) ;
811
- private readonly Queue < string > specialResponses = new Queue < string > ( ) ;
812
- private readonly AutoResetEvent inputReady = new AutoResetEvent ( false ) ;
811
+ private readonly AsyncProducerConsumerQueue < object > inputQueue = new AsyncProducerConsumerQueue < object > ( ) ; // string
812
+ private readonly AsyncProducerConsumerQueue < object > transQueue = new AsyncProducerConsumerQueue < object > ( ) ; // Transaction
813
+ private readonly ConcurrentQueue < string > specialResponses = new ConcurrentQueue < string > ( ) ;
813
814
private Transaction curTrans ;
814
815
815
816
public RealmIO ( Instance instance )
@@ -819,32 +820,21 @@ public RealmIO(Instance instance)
819
820
820
821
public void QueueInput ( string line )
821
822
{
822
- lock ( inputQueue )
823
- {
824
- inputQueue . Enqueue ( line ) ;
825
-
826
- if ( inputQueue . Count == 1 )
827
- inputReady . Set ( ) ;
828
- }
823
+ inputQueue . Enqueue ( line ) ;
829
824
}
830
825
831
826
public void QueueTransaction ( Transaction trans )
832
827
{
833
- lock ( transQueue )
834
- {
835
- transQueue . Enqueue ( trans ) ;
836
-
837
- if ( transQueue . Count == 1 )
838
- inputReady . Set ( ) ;
839
- }
828
+ transQueue . Enqueue ( trans ) ;
840
829
}
841
830
842
831
private static Regex chatRegex = new Regex ( @"^(-?\d+):\$(say|emote) (?:\>([^ ]*) )?(.*)$" ) ;
843
832
844
833
private async Task < string > GetInputLineAsync ( )
845
834
{
846
- if ( specialResponses . Count > 0 )
847
- return specialResponses . Dequeue ( ) ;
835
+ string specialResponse ;
836
+ if ( specialResponses . TryDequeue ( out specialResponse ) )
837
+ return specialResponse ;
848
838
849
839
instance . DisableWatchdog ( ) ;
850
840
@@ -866,65 +856,65 @@ private async Task<string> GetInputLineAsync()
866
856
curTrans = null ;
867
857
}
868
858
859
+ var queues = new AsyncProducerConsumerQueue < object > [ ] { transQueue , inputQueue } ;
860
+
869
861
do
870
862
{
871
- // is there a transaction waiting?
872
- lock ( transQueue )
863
+ // wait for a transaction or a line of player input
864
+ var dqResult = await queues . TryDequeueFromAnyAsync ( ) ;
865
+
866
+ if ( ! dqResult . Success )
867
+ throw new InvalidOperationException ( "failed to get input" ) ;
868
+
869
+ if ( dqResult . Queue == transQueue )
873
870
{
874
- if ( transQueue . Count > 0 )
875
- {
876
- curTrans = transQueue . Dequeue ( ) ;
877
- instance . logger . LogMessage ( LogLevel . Spam ,
878
- "Transaction in {0}: {1}" ,
879
- instance . name , curTrans . Query ) ;
880
- return curTrans . Query ;
881
- }
871
+ // got a transaction
872
+ curTrans = ( Transaction ) dqResult . Item ;
873
+ instance . logger . LogMessage ( LogLevel . Spam ,
874
+ "Transaction in {0}: {1}" ,
875
+ instance . name , curTrans . Query ) ;
876
+ return curTrans . Query ;
882
877
}
883
-
884
- // is there a line of player input waiting?
885
- lock ( inputQueue )
878
+ else
886
879
{
887
- if ( inputQueue . Count > 0 )
888
- {
889
- string line = inputQueue . Dequeue ( ) ;
890
- instance . logger . LogMessage ( LogLevel . Spam ,
891
- "Processing in {0}: {1}" ,
892
- instance . name , line ) ;
880
+ Contract . Assert ( dqResult . Queue == inputQueue ) ;
881
+
882
+ // got a line of player input
883
+ string line = ( string ) dqResult . Item ;
884
+ instance . logger . LogMessage ( LogLevel . Spam ,
885
+ "Processing in {0}: {1}" ,
886
+ instance . name , line ) ;
893
887
894
- if ( ! instance . rawMode )
888
+ if ( ! instance . rawMode )
889
+ {
890
+ if ( line . StartsWith ( "$silent " ) )
895
891
{
896
- if ( line . StartsWith ( "$silent " ) )
897
- {
898
- // set up a fake transaction so the output will be hidden
899
- // and the next line's output substituted instead
900
- line = line . Substring ( 8 ) ;
901
- curTrans = new DisambigHelper ( instance , line ) ;
902
- }
903
- else
892
+ // set up a fake transaction so the output will be hidden
893
+ // and the next line's output substituted instead
894
+ line = line . Substring ( 8 ) ;
895
+ curTrans = new DisambigHelper ( instance , line ) ;
896
+ }
897
+ else
898
+ {
899
+ Match m = chatRegex . Match ( line ) ;
900
+ if ( m . Success )
904
901
{
905
- Match m = chatRegex . Match ( line ) ;
906
- if ( m . Success )
907
- {
908
- string id = m . Groups [ 1 ] . Value ;
909
- string type = m . Groups [ 2 ] . Value ;
910
- string target = m . Groups [ 3 ] . Value ;
911
- string msg = m . Groups [ 4 ] . Value ;
912
- instance . chatTargetRegister = target ;
913
- instance . chatMsgRegister = msg ;
914
- line = id + ":$" + type ;
915
- }
902
+ string id = m . Groups [ 1 ] . Value ;
903
+ string type = m . Groups [ 2 ] . Value ;
904
+ string target = m . Groups [ 3 ] . Value ;
905
+ string msg = m . Groups [ 4 ] . Value ;
906
+ instance . chatTargetRegister = target ;
907
+ instance . chatMsgRegister = msg ;
908
+ line = id + ":$" + type ;
916
909
}
917
910
}
911
+ }
918
912
919
- if ( line . Length > MAX_LINE_LENGTH )
920
- line = line . Substring ( 0 , MAX_LINE_LENGTH ) ;
913
+ if ( line . Length > MAX_LINE_LENGTH )
914
+ line = line . Substring ( 0 , MAX_LINE_LENGTH ) ;
921
915
922
- return line ;
923
- }
916
+ return line ;
924
917
}
925
-
926
- // wait for input and then continue the loop
927
- inputReady . WaitOne ( ) ;
928
918
} while ( true ) ;
929
919
}
930
920
finally
0 commit comments