Help in GUI should also use Chat.Format and should still show ampersands that are not followed by a valid colour code

This commit is contained in:
UnknownShadow200 2020-11-28 22:27:20 +11:00
parent 84da13d10a
commit 3bbfe03789
4 changed files with 236 additions and 22 deletions

View File

@ -112,7 +112,7 @@ namespace MCGalaxy.Gui {
void GetHelp(string toHelp) {
ConsoleHelpPlayer p = new ConsoleHelpPlayer();
Command.Find("Help").Use(p, toHelp);
Popup.Message(Colors.Strip(p.Messages), "Help for /" + toHelp);
Popup.Message(Colors.StripUsed(p.Messages), "Help for /" + toHelp);
}
}
@ -125,6 +125,7 @@ namespace MCGalaxy.Gui {
}
public override void Message(byte type, string message) {
message = Chat.Format(message, this);
Messages += message + "\r\n";
}
}

View File

@ -245,8 +245,8 @@ namespace MCGalaxy {
}
}
/// <summary> Removes all instances of % or &amp; and the character that follows.
/// Does *not* check if the character pair makes a real color </summary>
/// <summary> Removes all occurrences of % or &amp; and the following character. </summary>
/// <remarks> Does NOT check if the following character is actually a valid color code. </remarks>
public static string Strip(string value) {
if (value.IndexOf('%') == -1 && value.IndexOf('&') == -1) return value;
char[] output = new char[value.Length];
@ -255,7 +255,7 @@ namespace MCGalaxy {
for (int i = 0; i < value.Length; i++) {
char token = value[i];
if (token == '%' || token == '&') {
i++; // Skip over the following color code.
i++; // Skip over the following color code
} else {
output[usedChars++] = token;
}
@ -263,8 +263,7 @@ namespace MCGalaxy {
return new string(output, 0, usedChars);
}
/// <summary> Removes all colors that are currently used.
/// This means % or &amp; may be kept if they are not followed a used color code </summary>
/// <summary> Removes all occurrences of % and &amp; that are followed by a used color code. </summary>
public static string StripUsed(string message) {
if (message.IndexOf('%') == -1 && message.IndexOf('&') == -1) return message;
char[] output = new char[message.Length];
@ -272,10 +271,9 @@ namespace MCGalaxy {
for (int i = 0; i < message.Length; i++) {
char c = message[i];
if ( (i < message.Length-1) &&
(c == '%' || c == '&') &&
(IsStandard(message[i+1]) || IsDefined(message[i+1])) ) {
i++; // Skip over the following color code.
if ((c == '%' || c == '&') && (i < message.Length - 1) &&
(IsStandard(message[i+1]) || IsDefined(message[i+1]))) {
i++; // Skip over the following color code
} else {
output[usedChars++] = c;
}

View File

@ -27,13 +27,12 @@ namespace MCGalaxy.Network {
/// <summary> Abstracts sending to/receiving from a network socket. </summary>
public abstract class INetSocket {
protected INetProtocol protocol;
protected INetProtocol protocol;
/// <summary> Whether the socket has been closed/disconnected. </summary>
public bool Disconnected;
/// <summary> The IP address of the remote end (i.e. client) of the socket. </summary>
public string IP;
/// <summary> Gets the IP address of the remote end (i.e. client) of the socket. </summary>
public abstract string IP { get; }
/// <summary> Sets whether this socket operates in low-latency mode (e.g. for TCP, disabes nagle's algorithm). </summary>
public abstract bool LowLatency { set; }
@ -129,8 +128,6 @@ namespace MCGalaxy.Network {
public TcpSocket(Socket s) {
socket = s;
IP = ((IPEndPoint)s.RemoteEndPoint).Address.ToString();
recvArgs.UserToken = this;
recvArgs.SetBuffer(recvBuffer, 0, recvBuffer.Length);
sendArgs.UserToken = this;
@ -143,6 +140,9 @@ namespace MCGalaxy.Network {
ReceiveNextAsync();
}
public override string IP {
get { return ((IPEndPoint)socket.RemoteEndPoint).Address.ToString(); }
}
public override bool LowLatency { set { socket.NoDelay = value; } }
@ -266,13 +266,11 @@ namespace MCGalaxy.Network {
public sealed class WebSocket : INetSocket, INetProtocol {
readonly INetSocket s;
public WebSocket(INetSocket socket) {
IP = socket.IP;
s = socket;
}
public WebSocket(INetSocket socket) { s = socket; }
// Init taken care by underlying socket
public override void Init() { }
public override string IP { get { return s.IP; } }
public override bool LowLatency { set { s.LowLatency = value; } }
bool readingHeaders = true;
@ -501,7 +499,6 @@ namespace MCGalaxy.Network {
SslStream ssl;
public SecureSocket(INetSocket socket) {
IP = socket.IP;
raw = socket;
wrapper = new WrapperStream();
@ -512,7 +509,8 @@ namespace MCGalaxy.Network {
}
// Init taken care by underlying socket
public override void Init() { }
public override void Init() { }
public override string IP { get { return raw.IP; } }
public override bool LowLatency { set { raw.LowLatency = value; } }
public override void Close() { raw.Close(); }
public void Disconnect() { Close(); }

View File

@ -0,0 +1,217 @@
/*
Copyright 2010 MCSharp team (Modified for use with MCZall/MCLawl/MCGalaxy)
Dual-licensed under the Educational Community License, Version 2.0 and
the GNU General Public License, Version 3 (the "Licenses"); you may
not use this file except in compliance with the Licenses. You may
obtain a copy of the Licenses at
http://www.opensource.org/licenses/ecl2.php
http://www.gnu.org/licenses/gpl-3.0.html
Unless required by applicable law or agreed to in writing,
software distributed under the Licenses are distributed on an "AS IS"
BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
or implied. See the Licenses for the specific language governing
permissions and limitations under the Licenses.
*/
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Security.Cryptography;
using System.Text;
using System.IO;
using System.Net.Security;
using System.Threading;
using System.Security.Cryptography.X509Certificates;
namespace MCGalaxy.Network {
/// <summary> Abstracts WebSocket protocol handling. </summary>
public abstract class WebSocket2 : INetProtocol {
bool readingHeaders = true;
bool conn, upgrade, version, proto;
string verKey;
void AcceptConnection() {
const string fmt =
"HTTP/1.1 101 Switching Protocols\r\n" +
"Upgrade: websocket\r\n" +
"Connection: Upgrade\r\n" +
"Sec-WebSocket-Accept: {0}\r\n" +
"Sec-WebSocket-Protocol: ClassiCube\r\n" +
"\r\n";
string key = verKey + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
SHA1 sha = SHA1.Create();
byte[] raw = sha.ComputeHash(Encoding.ASCII.GetBytes(key));
string headers = String.Format(fmt, Convert.ToBase64String(raw));
SendData(Encoding.ASCII.GetBytes(headers));
readingHeaders = false;
}
void ProcessHeader(string raw) {
// end of headers
if (raw.Length == 0) {
if (conn && upgrade && version && proto && verKey != null) {
AcceptConnection();
} else {
// don't pretend to be a http server (so IP:port isn't marked as one by bots)
Close();
}
}
int sep = raw.IndexOf(':');
if (sep == -1) return; // not a proper header
string key = raw.Substring(0, sep);
string val = raw.Substring(sep + 1).Trim();
if (key.CaselessEq("Connection")) {
conn = val.CaselessContains("Upgrade");
} else if (key.CaselessEq("Upgrade")) {
upgrade = val.CaselessEq("websocket");
} else if (key.CaselessEq("Sec-WebSocket-Version")) {
version = val.CaselessEq("13");
} else if (key.CaselessEq("Sec-WebSocket-Key")) {
verKey = val;
} else if (key.CaselessEq("Sec-WebSocket-Protocol")) {
proto = val.CaselessEq("ClassiCube");
}
}
int ReadHeaders(byte[] buffer, int bufferLen) {
int i;
for (i = 0; i < bufferLen - 1; ) {
int end = -1;
// find end of header
for (int j = i; j < bufferLen - 1; j++) {
if (buffer[j] != '\r' || buffer[j + 1] != '\n') continue;
end = j; break;
}
if (end == -1) break;
string value = Encoding.ASCII.GetString(buffer, i, end - i);
ProcessHeader(value);
i = end + 2;
}
return i;
}
int state, opcode, frameLen, maskRead, frameRead;
byte[] mask = new byte[4], frame;
const int state_header1 = 0;
const int state_header2 = 1;
const int state_extLen1 = 2;
const int state_extLen2 = 3;
const int state_mask = 4;
const int state_data = 5;
void DecodeFrame() {
for (int i = 0; i < frameLen; i++) {
frame[i] ^= mask[i & 3];
}
switch (opcode) {
// TODO: reply to ping frames
case 0x00:
case 0x02:
if (frameLen == 0) return;
HandleReceived(frame, frameLen);
break;
case 0x08:
// Connection is getting closed
Disconnect(1000); break;
default:
Disconnect(1003); break;
}
}
int ProcessData(byte[] data, int offset, int len) {
switch (state) {
case state_header1:
if (offset >= len) break;
opcode = data[offset++] & 0x0F;
state = state_header2;
goto case state_header2;
case state_header2:
if (offset >= len) break;
int flags = data[offset++] & 0x7F;
if (flags == 127) {
// unsupported 8 byte extended length
Disconnect(1009);
return len;
} else if (flags == 126) {
// two byte extended length
state = state_extLen1;
goto case state_extLen1;
} else {
// length is inline
frameLen = flags;
state = state_mask;
goto case state_mask;
}
case state_extLen1:
if (offset >= len) break;
frameLen = data[offset++] << 8;
state = state_extLen2;
goto case state_extLen2;
case state_extLen2:
if (offset >= len) break;
frameLen |= data[offset++];
state = state_mask;
goto case state_mask;
case state_mask:
for (; maskRead < 4; maskRead++) {
if (offset >= len) return offset;
mask[maskRead] = data[offset++];
}
state = state_data;
goto case state_data;
case state_data:
if (frame == null || frameLen > frame.Length) frame = new byte[frameLen];
int copy = Math.Min(len - offset, frameLen - frameRead);
Buffer.BlockCopy(data, offset, frame, frameRead, copy);
offset += copy; frameRead += copy;
if (frameRead == frameLen) {
DecodeFrame();
maskRead = 0;
frameRead = 0;
state = state_header1;
}
break;
}
return offset;
}
int INetProtocol.ProcessReceived(byte[] buffer, int bufferLen) {
int offset = 0;
if (readingHeaders) {
offset = ReadHeaders(buffer, bufferLen);
if (readingHeaders) return offset;
}
while (offset < bufferLen) {
offset = ProcessData(buffer, offset, bufferLen);
}
return offset;
}
public void Disconnect() { Disconnect(1000); }
protected abstract void HandleReceived(byte[] data, int len);
protected abstract void Disconnect(int reason);
protected abstract void SendData(byte[] data);
}
}