feat: initial commit - HJHA game server full source

6 major server modules (PdkFriendServer/GlobalSever/ServerCore/GameModule/GameNetModule) +
game logic (GameFix/GameDAL/ServerData) +
network layer (NetWorkMessage) +
data layer (ObjectModel) +
utilities (MrWu/Core/Config/CloudAPI/dll) +
adapters (zyxAdapter/base)

.NET 8.0 C# solution, 16 projects, 958 source files
This commit is contained in:
2026-07-07 12:02:15 +08:00
commit e9616125ce
958 changed files with 158203 additions and 0 deletions

View File

@ -0,0 +1,722 @@
using System;
using System.Collections.Generic;
using System.Linq;
using GameMessage;
namespace GameFix.Poker
{
public static class PokerLogic
{
public class XY
{
public int x; //牌面大小
public int y; //次数
}
/// <summary>
/// 获取所有的单张
/// </summary>
/// <returns></returns>
public static List<T> GetDanZhang<T>(IPlayOutCardType1 outCard, T[] cards, bool chaiDan = false)
where T : ICardInfoType1
{
if (outCard.GameNum <= 0 || cards == null || cards.Length <= 0) return null;
Dictionary<byte, byte> dic = new Dictionary<byte, byte>();
List<T> result = new List<T>();
foreach (var item in cards)
{
if (item.GameNum <= outCard.GameNum) continue;
if (dic.ContainsKey(item.GameNum))
{
if (dic[item.GameNum] == 1)
{
dic[item.GameNum]++;
if (!chaiDan || (chaiDan && dic[item.GameNum] >= 4))
result.RemoveAll(x => x.GameNum == item.GameNum);
}
}
else
{
dic[item.GameNum] = 1;
result.Add(item);
}
}
return result;
}
/// <summary>
/// 获取连续的相同大小的张数
/// </summary>
/// <param name="outCard"></param>
/// <param name="cards">手里没有打下去的牌</param>
/// <param name="count">几张大小相同的个数</param>
/// <param name="shouPai">手里全部的牌</param>
/// <returns></returns>
public static List<List<T>> GetLianCount<T>(IPlayOutCardType1 outCard, T[] cards, int count,
T[] shouPai) where T : ICardInfoType1
{
if (outCard.GameNum <= 0 || cards == null || cards.Length <= 3) return null;
int lian = 0; //连了几下
if (outCard.Type == CardType1.LianDui)
{
lian = outCard.Ids.Length / 2; //是几连对
}
if (outCard.Type == CardType1.FeiJi)
{
lian = GetFeiJiCount(GetCardByIds(shouPai, outCard.Ids)); //是几连飞机
}
List<List<T>> result = new List<List<T>>();
var countCard = GetCountCard(outCard, cards, count, true, true, lian - 2);
if (countCard.Count < lian) return result;
for (int i = 0; i < countCard.Count - 1; i++)
{
List<T> temp = new List<T>();
int c = 1;
int num = countCard[i][0].GameNum;
temp.AddRange(countCard[i]);
for (int j = i + 1; j < countCard.Count; j++)
{
if (countCard[j][0].GameNum + 1 == num)
{
temp.AddRange(countCard[j]);
c++;
num = countCard[j][0].GameNum;
}
if (c == lian) break;
}
if (c == lian)
{
result.Add(temp);
}
}
return result;
}
/// <summary>
/// 根据牌的绝对Id返回牌的详细信息
/// </summary>
/// <param name="wanshouPai">玩家手牌</param>
/// <param name="ids">牌的Id集合</param>
/// <returns></returns>
public static T[] GetCardByIds<T>(T[] wanshouPai, byte[] ids) where T : ICardInfoType1
{
if (ids == null || ids.Length <= 0) return null;
if (wanshouPai == null || wanshouPai.Length <= 0) return null;
List<T> result = new List<T>();
foreach (var id in ids)
{
foreach (var item in wanshouPai)
{
if (item.ID == id)
{
result.Add(item);
break;
}
}
}
if (ids.Length != result.Count)
{
throw new Exception($"获取玩家的牌张数不对 idslen:{ids.Length} result len:{result.Count} ");
}
return result.ToArray();
}
/// <summary>
/// 获取飞机的连的个数,长度
/// </summary>
/// <param name="selectCards"></param>
/// <returns></returns>
public static int GetFeiJiCount<T>(T[] selectCards) where T : ICardInfoType1
{
if (selectCards == null || selectCards.Length < 6) return 0;
List<XY> list = new List<XY>();
foreach (var item in selectCards)
{
var t = list.Find(x => x.x == item.GameNum);
if (t != null)
{
t.y++;
}
else
{
list.Add(new XY { x = item.GameNum, y = 1 });
}
}
int num = list.Count(x => x.y >= 3);
if (num < 2) return 0;
list = list.Where(x => x.y >= 3).ToList();
List<int> fj = new List<int>();
for (int i = 0; i < list.Count - 1; i++)
{
if (list[i].x - 1 == list[i + 1].x)
{
if (!fj.Contains(list[i].x))
{
fj.Add(list[i].x);
}
if (!fj.Contains(list[i + 1].x))
{
fj.Add(list[i + 1].x);
}
}
}
return fj.Count;
}
/// <summary>
/// 获取玩家手里几张相同的牌型
/// </summary>
/// <param name="outCard">玩家出的牌</param>
/// <param name="cards">玩家手里没有出下去的牌</param>
/// <param name="count">要获取相同大小的张数</param>
/// <param name="chai">是否拆牌 false不拆 true拆</param>
/// <param name="deng">是否获取跟出牌大小相等的牌 true是 false不是</param>
/// <returns></returns>
public static List<List<T>> GetCountCard<T>(IPlayOutCardType1 outCard, T[] cards, int count,
bool chai = false, bool deng = false, int cha = 0) where T : ICardInfoType1
{
if (count <= 0 || outCard.GameNum <= 0 || cards == null || cards.Length < count) return null;
List<List<T>> result = new List<List<T>>();
Dictionary<byte, byte> dic = new Dictionary<byte, byte>();
foreach (var item in cards)
{
if (deng)
{
if (item.GameNum < outCard.GameNum - cha) continue;
}
else
{
if (item.GameNum <= outCard.GameNum - cha) continue;
}
if (dic.ContainsKey(item.GameNum))
{
dic[item.GameNum]++;
}
else
{
dic[item.GameNum] = 1;
}
}
foreach (var item in dic)
{
if (item.Value >= 4 && count < 4 && chai) continue; //炸弹就不拆
if (!chai)
{
if (item.Value != count) continue;
result.Add(cards.Where(x => x.GameNum == item.Key).ToList());
}
else
{
if (item.Value < count) continue;
result.Add(cards.Where(x => x.GameNum == item.Key).Take(count).ToList());
}
}
return result;
}
/// <summary>
/// 是否是对子
/// 跑得快朋友房使用了
/// </summary>
/// <param name="selectCards"></param>
/// <returns></returns>
public static bool IsDuiZi<T>(T[] selectCards) where T : ICardInfoType1
{
if (selectCards == null || selectCards.Length != 2) return false;
return selectCards[0].GameNum == selectCards[1].GameNum;
}
/// <summary>
/// 获取顺子
/// </summary>
/// <param name="playCard"></param>
/// <returns></returns>
public static List<List<T>> GetShunZi<T>(T[] playCard) where T : ICardInfoType1
{
if (playCard == null || playCard.Length < 5) return null;
var cards = playCard.ToList();
List<List<T>> result = new List<List<T>>();
for (int i = 14; i > 6; i--)
{
List<T> shunzi = new List<T>();
for (int j = 0; j < playCard.Length; j++)
{
T temp = cards.FirstOrDefault(x => x.GameNum == (i - j));
if (temp.ID > 0)
{
shunzi.Add(temp);
}
else
{
break;
}
}
if (shunzi.Count >= 5)
{
result.Add(shunzi);
}
}
return result;
}
/// <summary>
/// 获取顺子
/// </summary>
/// <param name="outCard"></param>
/// <param name="playCard"></param>
/// <returns></returns>
public static List<List<T>> GetShunZi<T>(IPlayOutCardType1 outCard, T[] playCard) where T : ICardInfoType1
{
if (outCard.GameNum <= 0 || outCard.Type != CardType1.ShunZi) return null;
if (playCard == null || playCard.Length < outCard.Ids.Length) return null;
var cards = playCard.ToList();
List<List<T>> result = new List<List<T>>();
for (int i = 14; i > outCard.GameNum; i--)
{
List<T> shunzi = new List<T>();
for (int j = 0; j < outCard.Ids.Length; j++)
{
T temp = cards.FirstOrDefault(x => x.GameNum == (i - j));
if (temp.ID > 0)
{
shunzi.Add(temp);
}
else
{
break;
}
}
if (shunzi.Count == outCard.Ids.Length)
{
result.Add(shunzi);
}
}
return result;
}
/// <summary>
/// 是否是飞机 跑得快朋友房使用了
/// </summary>
/// <param name="selectCards">选中的牌</param>
/// <param name="isPaiBuGou">true不够 false 够</param>
/// <param name="canDaiPia">true可以带牌 false不可以带牌</param>
/// <param name="gameNum">返回飞机面值</param>
/// <returns></returns>
public static bool IsFeiJi<T>(T[] selectCards, bool isPaiBuGou, bool canDaiPia, out byte gameNum)
where T : ICardInfoType1
{
gameNum = 0;
if (selectCards == null || selectCards.Length < 6) return false;
List<XY> list = new List<XY>();
foreach (var item in selectCards)
{
var t = list.Find(x => x.x == item.GameNum);
if (t != null)
{
t.y++;
if (t.y >= 3)
{
if (gameNum == 0)
gameNum = item.GameNum;
}
}
else
{
list.Add(new XY { x = item.GameNum, y = 1 });
}
}
int num = list.Count(x => x.y >= 3);
if (num < 2)
return false; //if (canDaiPia && isPaiBuGou && selectCards.Length < num * 3) return false; //功能相同
list = list.Where(x => x.y >= 3).ToList();
List<int> fj = new List<int>();
for (int i = 0; i < list.Count - 1; i++)
{
if (list[i].x - 1 == list[i + 1].x)
{
if (!fj.Contains(list[i].x))
{
fj.Add(list[i].x);
}
if (!fj.Contains(list[i + 1].x))
{
fj.Add(list[i + 1].x);
}
}
}
num = fj.Count;
if (num < 2) return false;
gameNum = (byte)fj[0];
if (!canDaiPia && num * 3 != selectCards.Length) return false; //如果不能带牌
if (selectCards.Length > num * 3 + num * 2) return false; //带多了
if (canDaiPia && !isPaiBuGou && num * 3 + num * 2 != selectCards.Length) return false;
num--;
for (int i = 0; i < fj.Count; i++)
{
if (num == 1)
{
//2连的飞机
return fj[i] - num == fj[i + num];
}
else if (num == 2)
{
//3连的飞机
return fj[i] == fj[i + 1] + 1 && fj[i + 1] == fj[i + 2] + 1;
}
else if (num == 3)
{
//4连的飞机
return fj[i] == fj[i + 1] + 1 && fj[i + 1] == fj[i + 2] + 1 && fj[i + 2] == fj[i + 3] + 1;
}
else
{
if (fj[i] - num != fj[i + num])
{
return false;
}
}
}
return true;
}
/// <summary>
/// 判断是否是顺子,使用该函数前请先排序 跑得快朋友房使用了
/// </summary>
/// <param name="selectCards"></param>
/// <returns></returns>
public static bool IsShunzi<T>(T[] selectCards) where T : ICardInfoType1
{
if (selectCards == null || selectCards.Length < 5) return false;
T temp = selectCards[0];
for (int i = 1; i < selectCards.Length; i++)
{
if (selectCards[i].GameNum != temp.GameNum - 1) return false; //不是连续的
temp = selectCards[i];
}
return true;
}
/// <summary>
/// 给牌排序 跑得快朋友房使用了
/// </summary>
/// <param name="cards"></param>
public static void SortCardByGameNum<T>(ref T[] cards) where T : ICardInfoType1
{
if (cards == null || cards.Length < 2) return;
Array.Sort(cards, (x, y) => y.GameNum.CompareTo(x.GameNum));
}
/// <summary>
/// 是否是连对,,使用该函数前请先排序 跑得快朋友房使用了
/// </summary>
/// <param name="selectCards"></param>
/// <returns></returns>
public static bool IsLianDui<T>(T[] selectCards) where T : ICardInfoType1
{
if (selectCards == null || selectCards.Length < 4 || selectCards.Length % 2 != 0) return false;
T temp = selectCards[0];
for (int i = 0; i < selectCards.Length; i += 2)
{
if (selectCards[i].GameNum != selectCards[i + 1].GameNum) return false; //不是一对的牌
if (i + 2 <= selectCards.Length - 1)
{
if (temp.GameNum != selectCards[i + 2].GameNum + 1) return false; //不是顺子
temp = selectCards[i + 2];
}
}
return true;
}
/// <summary>
/// 获取玩家炸弹没有炸弹则out就是废王的牌
/// 需要先排序才可以运算
/// </summary>
/// <param name="playCards">玩家手牌</param>
/// <param name="cards">炸弹的牌 或者 废王的牌</param>
/// <returns>true有炸弹 false没有炸弹</returns>
public static bool GetPlayZhaDan<T>(T[] playCards, out List<T> cards) where T : ICardInfoType1
{
cards = new List<T>();
if (playCards == null || playCards.Length <= 0) return false;
List<T> result = new List<T>();
List<T> temp = new List<T>();
List<T> wang = new List<T>();
byte count = 0;
byte num = 0;
foreach (var item in playCards)
{
if (item.GameNum == 98 || item.GameNum == 100)
{
wang.Add(item);
continue;
}
if (num == 0 && count == 0)
{
num = item.GameNum;
count++;
temp.Add(item);
}
else
{
if (num == item.GameNum)
{
count++;
temp.Add(item);
}
else
{
num = item.GameNum;
count = 1;
if (temp.Count >= 4)
{
result.AddRange(temp);
}
temp.Clear();
temp.Add(item);
}
}
}
if (temp.Count >= 4) //防止最后一张牌遗漏
{
result.AddRange(temp);
}
temp.Clear();
if (result.Count >= 4)
{
result.AddRange(wang);
cards.AddRange(result);
return true;
}
cards = wang;
if (wang.Count >= 4)
{
return true;
}
return false;
}
/// <summary>
/// 获取玩家的炸弹
/// </summary>
/// <param name="playCards">玩家手牌</param>
/// <param name="cards">炸弹的牌</param>
/// <returns>true有炸弹 false没有炸弹</returns>
public static bool GetPlayZhaDans<T>(T[] playCards, out List<List<T>> cards) where T : ICardInfoType1
{
cards = new List<List<T>>();
if (playCards == null || playCards.Length <= 0) return false;
List<T> temp = new List<T>();
byte count = 0;
byte num = 0;
foreach (var item in playCards)
{
if (num == 0 && count == 0)
{
num = item.GameNum;
count++;
temp.Add(item);
}
else
{
if (num == item.GameNum)
{
count++;
temp.Add(item);
}
else
{
num = item.GameNum;
count = 1;
if (temp.Count >= 4)
{
cards.Add(temp.ToList());
}
temp.Clear();
temp.Add(item);
}
}
}
if (temp.Count >= 4) //防止最后一张牌遗漏
{
cards.Add(temp.ToList());
}
return cards.Count > 0;
}
/// <summary>
/// 是否是三带二 跑得快朋友房使用了
/// </summary>
/// <param name="selectCards">要判断的牌</param>
/// <param name="isPaiBuGou">玩家手牌是不是不够张数带牌true不够 false够</param>
/// <returns></returns>
#pragma warning disable CS1573 // 参数在 XML 注释中没有匹配的 param 标记(但其他参数有)
public static bool IsSanDaiEr<T>(T[] selectCards, bool isPaiBuGou, out byte gameNum) where T : ICardInfoType1
#pragma warning restore CS1573 // 参数在 XML 注释中没有匹配的 param 标记(但其他参数有)
{
gameNum = 0;
if (selectCards == null || selectCards.Length < 4 || selectCards.Length > 5) return false;
if (!isPaiBuGou && selectCards.Length != 5) return false;
Dictionary<byte, byte> dic = new Dictionary<byte, byte>();
foreach (var item in selectCards)
{
if (dic.ContainsKey(item.GameNum))
{
dic[item.GameNum]++;
}
else
{
dic[item.GameNum] = 1;
}
}
if (dic.Count > 3 || dic.Count < 2) return false;
var b = false;
foreach (var item in dic)
{
if (item.Value >= 3 && item.Key < 90) //大王不能当成3个一起出
{
gameNum = item.Key;
b = true;
break;
}
}
return b;
}
/// <summary>
/// 检测是否有相同的ID因为牌的ID是唯一的不会相同
/// </summary>
/// <param name="ids"></param>
/// <returns>true有 false没有</returns>
public static bool CheckSameId(byte[] ids)
{
if (ids == null || ids.Length <= 1) return false;
Dictionary<byte, int> did = new Dictionary<byte, int>();
for (int i = 0; i < ids.Length; i++)
{
if (did.ContainsKey(ids[i]))
{
did[ids[i]]++;
}
else
{
did[ids[i]] = 1;
}
}
foreach (var id in did)
{
if (id.Value > 1)
{
return true;
}
}
return false;
}
/// <summary>
/// 给牌排序,按照个数从大到小
/// </summary>
/// <param name="cards"></param>
/// <returns></returns>
public static T[] SortCardByCount<T>(T[] cards) where T : ICardInfoType1
{
if (cards == null || cards.Length <= 0) return null;
List<T> result = new List<T>();
Dictionary<int, List<T>> dics = new Dictionary<int, List<T>>();
for (int i = 0; i < cards.Length; i++)
{
if (cards[i].GameNum > 20)
{
result.Add(cards[i]);
continue;
}
if (dics.ContainsKey(cards[i].GameNum))
{
dics[cards[i].GameNum].Add(cards[i]);
}
else
{
var temp = new List<T>();
temp.Add(cards[i]);
dics.Add(cards[i].GameNum, temp);
}
}
var newdics = dics.OrderByDescending(x => x.Value.Count);
foreach (var item in newdics)
{
result.AddRange(item.Value);
}
return result.ToArray();
}
public static string GetGameNumToString(byte gameNum)
{
string result = "";
if (gameNum <= 0) return result;
if (gameNum >= 3 && gameNum <= 10)
{
result = gameNum.ToString();
}
else
{
switch (gameNum)
{
case 11:
result = "J";
break;
case 12:
result = "Q";
break;
case 13:
result = "K";
break;
case 14:
result = "A";
break;
case 16:
result = "2";
break;
//叫牌中不会有大小王
}
}
return result;
}
}
}