本文聚焦 Server 端處理「叫地主/不叫」邏輯的兩個接收執行緒 AcceptClient1Data、AcceptClient2Data,以及 Server 玩家自身的按鈕事件處理。
public void AcceptClient1Data() {
var ns = _client1.GetStream();
while (true) {
byte[] buffer = new byte[108];
ns.Read(buffer, 0, buffer.Length);
string msg = Encoding.Default.GetString(buffer);
if (msg.StartsWith("AreYouLandLord")) { // Client1 回應「不叫」
if (DConsole.LandLordNum == 1) { // 若預設地主是 Server 自己,則 Client1 為最後一人,重新發牌
DConsole.Restart(); continue;
}
DConsole.Player1.AreYouLandLord = true; // 轉給 Server 叫
continue;
}
if (msg.StartsWith("IamLandLord")) { // Client1 叫地主
UpdateUILandLord(1);
SendDataForClient("ClientIsLandLord", 2); // 通知 Client2
SendLandLordPokersToAll();
DConsole.Player1.SelectLandLordEnd();
continue;
}
}
}
public void AcceptClient2Data() {
var ns = _client2.GetStream();
while (true) {
byte[] buffer = new byte[108];
ns.Read(buffer, 0, buffer.Length);
string msg = Encoding.Default.GetString(buffer);
if (msg.StartsWith("AreYouLandLord")) { // Client2 回應「不叫」
if (DConsole.LandLordNum == 2) { DConsole.Restart(); continue; }
SendDataForClient("AreYouLandLord", 1); // 轉給 Client1
continue;
}
if (msg.StartsWith("IamLandLord")) { // Client2 叫地主
UpdateUILandLord(2);
SendLandLordPokersToAll();
SendDataForClient("ClientIsLandLord", 1);
DConsole.Player1.SelectLandLordEnd();
continue;
}
}
}
private void btnNotLandLord_Click(object sender, EventArgs e) {
Player1.AreYouLandLord = false; Player1.IsLandLord = false;
HideLandLordButtons();
if (Server != null) { // 我是 Server
if (DConsole.LandLordNum == 3) { DConsole.Restart(); return; } // 我是最後一位
Server.SendDataForClient("AreYouLandLord", 2); // 轉給 Client2
}
if (Client != null) { // 我是 Client (理論上不會進這裡)
Client.SendDataForServer("AreYouLandLord");
}
}
權限傳遞順序由隨機數決定:
LandLordNum = 1:Server → Client2 → Client1LandLordNum = 2:Client1 → Server → Client2LandLordNum = 3:Client2 → Client1 → Server若輪到最後一人仍「不叫」 → Restart() 重新發牌。
⚠️ 原始碼大量使用
Thread.Sleep硬性延遲、StartsWith字串比對、固定緩衝區讀取、UI 邏輯與網路邏輯強耦合 (DConsole靜態類別)。實務專案請參考前文「改進建議」重構。