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,4 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
</configuration>

View File

@ -0,0 +1,3 @@
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<Costura />
</Weavers>

View File

@ -0,0 +1,176 @@
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. -->
<xs:element name="Weavers">
<xs:complexType>
<xs:all>
<xs:element name="Costura" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:all>
<xs:element minOccurs="0" maxOccurs="1" name="ExcludeAssemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of assembly names to exclude from the default action of "embed all Copy Local references", delimited with line breaks</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element minOccurs="0" maxOccurs="1" name="IncludeAssemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of assembly names to include from the default action of "embed all Copy Local references", delimited with line breaks.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element minOccurs="0" maxOccurs="1" name="ExcludeRuntimeAssemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of runtime assembly names to exclude from the default action of "embed all Copy Local references", delimited with line breaks</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element minOccurs="0" maxOccurs="1" name="IncludeRuntimeAssemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of runtime assembly names to include from the default action of "embed all Copy Local references", delimited with line breaks.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element minOccurs="0" maxOccurs="1" name="Unmanaged32Assemblies" type="xs:string">
<xs:annotation>
<xs:documentation>Obsolete, use UnmanagedWinX86Assemblies instead</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element minOccurs="0" maxOccurs="1" name="UnmanagedWinX86Assemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of unmanaged X86 (32 bit) assembly names to include, delimited with line breaks.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element minOccurs="0" maxOccurs="1" name="Unmanaged64Assemblies" type="xs:string">
<xs:annotation>
<xs:documentation>Obsolete, use UnmanagedWinX64Assemblies instead.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element minOccurs="0" maxOccurs="1" name="UnmanagedWinX64Assemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of unmanaged X64 (64 bit) assembly names to include, delimited with line breaks.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element minOccurs="0" maxOccurs="1" name="UnmanagedWinArm64Assemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of unmanaged Arm64 (64 bit) assembly names to include, delimited with line breaks.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element minOccurs="0" maxOccurs="1" name="PreloadOrder" type="xs:string">
<xs:annotation>
<xs:documentation>The order of preloaded assemblies, delimited with line breaks.</xs:documentation>
</xs:annotation>
</xs:element>
</xs:all>
<xs:attribute name="CreateTemporaryAssemblies" type="xs:boolean">
<xs:annotation>
<xs:documentation>This will copy embedded files to disk before loading them into memory. This is helpful for some scenarios that expected an assembly to be loaded from a physical file.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="IncludeDebugSymbols" type="xs:boolean">
<xs:annotation>
<xs:documentation>Controls if .pdbs for reference assemblies are also embedded.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="IncludeRuntimeReferences" type="xs:boolean">
<xs:annotation>
<xs:documentation>Controls if runtime assemblies are also embedded.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="UseRuntimeReferencePaths" type="xs:boolean">
<xs:annotation>
<xs:documentation>Controls whether the runtime assemblies are embedded with their full path or only with their assembly name.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="DisableCompression" type="xs:boolean">
<xs:annotation>
<xs:documentation>Embedded assemblies are compressed by default, and uncompressed when they are loaded. You can turn compression off with this option.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="DisableCleanup" type="xs:boolean">
<xs:annotation>
<xs:documentation>As part of Costura, embedded assemblies are no longer included as part of the build. This cleanup can be turned off.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="DisableEventSubscription" type="xs:boolean">
<xs:annotation>
<xs:documentation>The attach method no longer subscribes to the `AppDomain.AssemblyResolve` (.NET 4.x) and `AssemblyLoadContext.Resolving` (.NET 6.0+) events.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="LoadAtModuleInit" type="xs:boolean">
<xs:annotation>
<xs:documentation>Costura by default will load as part of the module initialization. This flag disables that behavior. Make sure you call CosturaUtility.Initialize() somewhere in your code.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="IgnoreSatelliteAssemblies" type="xs:boolean">
<xs:annotation>
<xs:documentation>Costura will by default use assemblies with a name like 'resources.dll' as a satellite resource and prepend the output path. This flag disables that behavior.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="ExcludeAssemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of assembly names to exclude from the default action of "embed all Copy Local references", delimited with |</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="IncludeAssemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of assembly names to include from the default action of "embed all Copy Local references", delimited with |.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="ExcludeRuntimeAssemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of runtime assembly names to exclude from the default action of "embed all Copy Local references", delimited with |</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="IncludeRuntimeAssemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of runtime assembly names to include from the default action of "embed all Copy Local references", delimited with |.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="Unmanaged32Assemblies" type="xs:string">
<xs:annotation>
<xs:documentation>Obsolete, use UnmanagedWinX86Assemblies instead</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="UnmanagedWinX86Assemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of unmanaged X86 (32 bit) assembly names to include, delimited with |.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="Unmanaged64Assemblies" type="xs:string">
<xs:annotation>
<xs:documentation>Obsolete, use UnmanagedWinX64Assemblies instead</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="UnmanagedWinX64Assemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of unmanaged X64 (64 bit) assembly names to include, delimited with |.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="UnmanagedWinArm64Assemblies" type="xs:string">
<xs:annotation>
<xs:documentation>A list of unmanaged Arm64 (64 bit) assembly names to include, delimited with |.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="PreloadOrder" type="xs:string">
<xs:annotation>
<xs:documentation>The order of preloaded assemblies, delimited with |.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:all>
<xs:attribute name="VerifyAssembly" type="xs:boolean">
<xs:annotation>
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="VerifyIgnoreCodes" type="xs:string">
<xs:annotation>
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="GenerateXsd" type="xs:boolean">
<xs:annotation>
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:schema>

40
PdkFriendServer/Form1.Designer.cs generated Normal file
View File

@ -0,0 +1,40 @@
namespace PdkFriendServer
{
partial class Form1
{
/// <summary>
/// 必需的设计器变量。
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// 清理所有正在使用的资源。
/// </summary>
/// <param name="disposing">如果应释放托管资源,为 true否则为 false。</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows
/// <summary>
/// 设计器支持所需的方法 - 不要修改
/// 使用代码编辑器修改此方法的内容。
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(800, 450);
this.Text = "Form1";
}
#endregion
}
}

20
PdkFriendServer/Form1.cs Normal file
View File

@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace PdkFriendServer
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
}
}

View File

@ -0,0 +1,26 @@
namespace GameFix.PaoDeKuaiF
{
public struct LogicMemory
{
/// <summary>
/// 朋友房打了第几局
/// </summary>
public int WarCount;
/// <summary>
/// 上游位置
/// </summary>
public byte ShangYou;
/// <summary>
/// 记录炸弹个数
/// </summary>
public byte BombCount;
public void Init()
{
WarCount = 0;
ShangYou = 0;
}
}
}

View File

@ -0,0 +1,624 @@
using System.Collections.Generic;
using System.Linq;
using GameFix.Poker;
using GameMessage;
using GameMessage.PaoDeKuaiF;
namespace GameFix.PaoDeKuaiF
{
/// <summary>
/// 跑得快牌运算逻辑
/// </summary>
public class PdkCardAlgorithm
{
/// <summary>
/// 获取提示的牌
/// </summary>
/// <param name="outCard">当前出的牌</param>
/// <param name="shoupai">玩家在手里的牌,没有出下去的牌</param>
/// <param name="maxShouPai">当前出牌人的手牌</param>
/// <param name="aaaIsZhaDan">3A是不是炸弹默认不是</param>
/// <param name="isOne">只要一种提示 true是 false不是</param>
/// <returns></returns>
public static List<List<TCardInfoPdkF>> GetTipCardByBtn(PlayOutCardPdkF outCard, TCardInfoPdkF[] shoupai,
TCardInfoPdkF[] maxShouPai, bool aaaIsZhaDan = false, bool isOne = false)
{
if (shoupai == null || shoupai.Length <= 0) return null;
List<List<TCardInfoPdkF>> result = new List<List<TCardInfoPdkF>>();
if (outCard.GameNum <= 0)
{
//如果是自己先出的话, 就从尾部一张一张提示过去
for (int i = shoupai.Length - 1; i >= 0; i--)
{
List<TCardInfoPdkF> chu = new List<TCardInfoPdkF>();
chu.Add(shoupai[i]);
result.Add(chu);
}
return result;
}
switch (outCard.Type)
{
case CardType1.DanZhang:
var danzhangs = PokerLogic.GetDanZhang(outCard, shoupai);
if (danzhangs == null || danzhangs.Count <= 0)
{
danzhangs = PokerLogic.GetDanZhang(outCard, shoupai, true);
}
if (danzhangs != null && danzhangs.Count > 0)
{
danzhangs.Sort((x, y) => x.GameNum.CompareTo(y.GameNum));
foreach (var item in danzhangs)
{
List<TCardInfoPdkF> chu = new List<TCardInfoPdkF> { item };
result.Add(chu);
}
}
break;
case CardType1.DuiZi:
result = PokerLogic.GetCountCard(outCard, shoupai, 2);
if (result == null || result.Count <= 0)
{
result = PokerLogic.GetCountCard(outCard, shoupai, 2, true);
}
if (result != null)
{
result.Sort((x, y) => x[0].GameNum.CompareTo(y[0].GameNum));
}
break;
case CardType1.SanDai2:
result = PokerLogic.GetCountCard(outCard, shoupai, 3, true);
if (result != null) result.Sort((x, y) => x[0].GameNum.CompareTo(y[0].GameNum));
break;
case CardType1.ShunZi:
result = PokerLogic.GetShunZi(outCard, shoupai);
if (result != null) result.Sort((x, y) => x[0].GameNum.CompareTo(y[0].GameNum));
break;
case CardType1.LianDui:
result = PokerLogic.GetLianCount(outCard, shoupai, 2, null);
if (result != null) result.Sort((x, y) => x[0].GameNum.CompareTo(y[0].GameNum));
break;
case CardType1.FeiJi:
result = PokerLogic.GetLianCount(outCard, shoupai, 3, maxShouPai);
if (result != null) result.Sort((x, y) => x[0].GameNum.CompareTo(y[0].GameNum));
break;
case CardType1.ZhaDan:
PokerLogic.GetPlayZhaDan(shoupai, out var cards);
if (cards.Count > 4)
{
int c = cards.Count / 4;
for (int i = 0; i < c; i++)
{
var tx = cards.Skip(i * 4).Take(4).ToList();
if (tx != null && tx[0].GameNum > outCard.GameNum)
{
result.Add(tx);
}
}
}
else
{
if (cards != null && cards.Count > 0 && cards[0].GameNum > outCard.GameNum)
{
result.Add(cards);
}
}
break;
}
if (isOne && result != null && result.Count > 0)
{
//只要一种提示
}
else
{
if (result == null) result = new List<List<TCardInfoPdkF>>();
if (aaaIsZhaDan)
{
var aaa = GetAAAZhaDan(shoupai);
if (aaa != null && aaa.Count >= 3)
{
result.Add(aaa);
}
}
if (outCard.Type != CardType1.ZhaDan)
{
PokerLogic.GetPlayZhaDan(shoupai, out var cards);
if (cards != null && cards.Count > 0)
{
int c = cards.Count / 4;
if (c <= 0)
{
result.Add(cards);
}
else
{
for (int i = 0; i < c; i++)
{
result.Add(cards.Skip(i * 4).Take(4).ToList());
}
}
}
}
}
return result;
}
/// <summary>
/// 获取提示的牌
/// </summary>
/// <param name="outCard">当前出的牌</param>
/// <param name="shoupai">玩家在手里的牌,没有出下去的牌</param>
/// <param name="maxShouPai">当前出牌人的手牌</param>
/// <param name="aaaIsZhaDan">3A是不是炸弹默认不是</param>
/// <param name="isOne">只要一种提示 true是 false不是</param>
/// <returns></returns>
public static List<List<TCardInfoPdkF>> GetTipCard(PlayOutCardPdkF outCard, TCardInfoPdkF[] shoupai, TCardInfoPdkF[] maxShouPai,
bool aaaIsZhaDan = false, bool isOne = false)
{
if (shoupai == null || shoupai.Length <= 0) return null;
List<List<TCardInfoPdkF>> result = new List<List<TCardInfoPdkF>>();
if (outCard.GameNum <= 0)
{
//如果是自己先出的话, 就从尾部一张一张提示过去
for (int i = shoupai.Length - 1; i >= 0; i--)
{
List<TCardInfoPdkF> chu = new List<TCardInfoPdkF>();
chu.Add(shoupai[i]);
result.Add(chu);
}
return result;
}
switch (outCard.Type)
{
//飞机带翅膀、炸弹,四带三、四带二
case CardType1.DanZhang:
var danzhangs = shoupai.Where(x => x.GameNum > outCard.GameNum);
if (danzhangs.Count() > 0)
{
foreach (var item in danzhangs)
{
List<TCardInfoPdkF> chu = new List<TCardInfoPdkF>();
chu.Add(item);
result.Add(chu);
}
}
break;
case CardType1.DuiZi:
result = PokerLogic.GetCountCard(outCard, shoupai, 2, true);
break;
case CardType1.SanDai2:
result = PokerLogic.GetCountCard(outCard, shoupai, 3, true);
break;
case CardType1.ShunZi:
result = PokerLogic.GetShunZi(outCard, shoupai);
break;
case CardType1.LianDui:
result = PokerLogic.GetLianCount(outCard, shoupai, 2, null);
break;
case CardType1.FeiJi:
result = PokerLogic.GetLianCount(outCard, shoupai, 3, maxShouPai);
break;
case CardType1.ZhaDan:
PokerLogic.GetPlayZhaDan(shoupai, out var cards);
if (cards != null && cards.Count > 0 && cards[0].GameNum > outCard.GameNum)
{
result.Add(cards);
}
break;
}
if (result == null) result = new List<List<TCardInfoPdkF>>();
if (isOne && result != null && result.Count > 0)
{
//只要一种提示
}
else
{
if (aaaIsZhaDan)
{
var aaa = GetAAAZhaDan(shoupai);
if (aaa != null && aaa.Count >= 3)
{
result.Add(aaa);
}
}
if (outCard.Type != CardType1.ZhaDan)
{
PokerLogic.GetPlayZhaDan(shoupai, out var cards);
if (cards != null && cards.Count > 0)
{
result.Add(cards);
}
}
}
return result;
}
/// <summary>
/// 判断是否是炸弹
/// </summary>
/// <param name="cards"></param>
/// <param name="aaaIsZhaDan"></param>
/// <param name="isCheckPaiCount"></param>
/// <returns></returns>
public static bool IsZhaDan(TCardInfoPdkF[] cards, bool aaaIsZhaDan, bool isCheckPaiCount = true)
{
if (cards == null || cards.Length < 3 || cards.Length > 4) return false;
if (aaaIsZhaDan && cards.Length == 3)
{
return Is3A(cards);
}
if (cards.Length == 4)
{
return IsZhaDan(cards, isCheckPaiCount);
}
return false;
}
/// <summary>
/// 检查玩家是否有比出的牌更大的牌
/// </summary>
/// <param name="outCard">玩家出的牌</param>
/// <param name="shouPai">自己的手牌-在手里的牌,并且是排序过的。</param>
/// <param name="maxShouPai">出牌人的手牌</param>
/// <param name="aaaIsZhaDan">3A是不是炸弹默认不是</param>
/// <returns>true有比玩家大的牌 false没有</returns>
public static bool CheckHaveBigger(PlayOutCardPdkF outCard, TCardInfoPdkF[] shouPai, TCardInfoPdkF[] maxShouPai,
bool aaaIsZhaDan = false)
{
if (shouPai == null || shouPai.Length <= 0) return false;
List<List<TCardInfoPdkF>> cs = null;
List<TCardInfoPdkF> cards = null;
switch (outCard.Type)
{
case CardType1.DanZhang:
if (shouPai.Where(x => x.GameNum > outCard.GameNum).Count() > 0)
{
return true;
}
break;
case CardType1.DuiZi:
cs = PokerLogic.GetCountCard(outCard, shouPai, 2, true);
if (cs != null && cs.Count > 0)
{
return true;
}
break;
case CardType1.SanDai2:
cs = PokerLogic.GetCountCard(outCard, shouPai, 3, true);
if (cs != null && cs.Count > 0)
{
return true;
}
break;
case CardType1.ShunZi:
cs = PokerLogic.GetShunZi(outCard, shouPai);
if (cs != null && cs.Count > 0)
{
return true;
}
break;
case CardType1.LianDui:
cs = PokerLogic.GetLianCount(outCard, shouPai, 2, null);
if (cs != null && cs.Count > 0)
{
return true;
}
break;
case CardType1.FeiJi:
cs = PokerLogic.GetLianCount(outCard, shouPai, 3, maxShouPai);
if (cs != null && cs.Count > 0)
{
return true;
}
break;
case CardType1.ZhaDan:
var b = PokerLogic.GetPlayZhaDan(shouPai, out cards);
if (!b) return false;
foreach (var item in cards)
{
if (item.GameNum > outCard.GameNum) return true;
}
break;
}
if (aaaIsZhaDan)
{
var aaa = GetAAAZhaDan(shouPai);
if (aaa != null && aaa.Count >= 3)
{
return true;
}
}
if (outCard.Type != CardType1.ZhaDan)
{
return PokerLogic.GetPlayZhaDan(shouPai, out cards);
}
return false;
}
/// <summary>
/// 通过选中的牌返回出下去牌的类型 否则选中的牌就不能出下去
/// 一般客户端用
/// </summary>
/// <param name="selectCards">选中的牌</param>
/// <param name="shouPai">玩家手牌,不包含已经出下去的牌</param>
/// <param name="wangfa">规则玩法</param>
/// <param name="paycard">返回出牌内容</param>
/// <returns>true可以出牌 false不能出牌</returns>
public static bool GetOutCard(TCardInfoPdkF[] selectCards, TCardInfoPdkF[] shouPai, PdkRule wangfa,
out PlayOutCardPdkF paycard)
{
paycard = new PlayOutCardPdkF();
if (selectCards == null || selectCards.Length <= 0 || shouPai == null || shouPai.Length <= 0) return false;
var chaCard = shouPai.Except(selectCards); //获取差集如果个数大于0说明牌的张数是够的如果是0说明牌不够
PokerLogic.SortCardByGameNum(ref selectCards);
var bugou = chaCard.Count() <= 0;
byte gameNum = 0;
if (selectCards.Length == 1)
{
//单张可以出
paycard.Ids = new byte[] { selectCards[0].ID };
paycard.GameNum = selectCards[0].GameNum;
paycard.Type = CardType1.DanZhang;
return true;
}
else if (selectCards.Length == 2)
{
//对子
if (PokerLogic.IsDuiZi(selectCards))
{
paycard.Ids = selectCards.Select(x => x.ID).ToArray();
paycard.GameNum = selectCards[0].GameNum;
paycard.Type = CardType1.DuiZi;
return true;
}
}
else if (selectCards.Length == 3)
{
if (wangfa.AAAIsZhaDan && Is3A(selectCards)) //3A是炸弹
{
paycard.Ids = selectCards.Select(x => x.ID).ToArray();
paycard.GameNum = selectCards[0].GameNum;
paycard.Type = CardType1.ZhaDan;
return true;
}
else
{
bool xt = selectCards[0].GameNum == selectCards[1].GameNum &&
selectCards[2].GameNum == selectCards[1].GameNum;
if (xt && bugou)
{
paycard.GameNum = selectCards[0].GameNum;
paycard.Type = CardType1.SanDai2;
paycard.Ids = selectCards.Select(x => x.ID).ToArray();
return true;
}
}
}
else
{
if (IsZhaDan(selectCards)) //炸弹
{
paycard.GameNum = selectCards[0].GameNum; //因为该值会根据大小排序
paycard.Type = CardType1.ZhaDan;
paycard.Ids = selectCards.Select(x => x.ID).ToArray();
return true;
}
if (wangfa.SiDai2 && IsSiDai2(selectCards, !bugou, out gameNum))
{
//四带二
paycard.GameNum = gameNum;
paycard.Type = CardType1.SiDai2;
paycard.Ids = selectCards.Select(x => x.ID).ToArray();
return true;
}
if (wangfa.SiDai3 && IsSiDai3(selectCards, !bugou, out gameNum))
{
//四带二
paycard.GameNum = gameNum;
paycard.Type = CardType1.SiDai3;
paycard.Ids = selectCards.Select(x => x.ID).ToArray();
return true;
}
if (PokerLogic.IsShunzi(selectCards))
{
//顺子
paycard.GameNum = selectCards[0].GameNum;
paycard.Type = CardType1.ShunZi;
paycard.Ids = selectCards.Select(x => x.ID).ToArray();
return true;
}
if (PokerLogic.IsLianDui(selectCards)) //连对
{
paycard.GameNum = selectCards[0].GameNum;
paycard.Type = CardType1.LianDui;
paycard.Ids = selectCards.Select(x => x.ID).ToArray();
return true;
}
if (PokerLogic.IsSanDaiEr(selectCards, bugou, out gameNum)) //三带二、
{
paycard.GameNum = gameNum;
paycard.Type = CardType1.SanDai2;
paycard.Ids = selectCards.Select(x => x.ID).ToArray();
return true;
}
if (PokerLogic.IsFeiJi(selectCards, bugou, true, out gameNum)) //飞机带翅膀
{
paycard.GameNum = gameNum;
paycard.Type = CardType1.FeiJi;
paycard.Ids = selectCards.Select(x => x.ID).ToArray();
return true;
}
}
return false;
}
/// <summary>
/// 是否是3张A
/// </summary>
/// <param name="cards"></param>
/// <returns>true是 false不是</returns>
static bool Is3A(TCardInfoPdkF[] cards)
{
if (cards == null || cards.Length != 3) return false;
return cards[0].GameNum == 14 && cards[1].GameNum == 14 && cards[2].GameNum == 14;
}
/// <summary>
/// 获取3A炸弹
/// </summary>
/// <param name="cards">玩家手里没有打下去的牌</param>
/// <returns></returns>
static List<TCardInfoPdkF> GetAAAZhaDan(TCardInfoPdkF[] cards)
{
if (cards == null || cards.Length < 3) return null;
List<TCardInfoPdkF> result = new List<TCardInfoPdkF>();
for (int i = 0; i < cards.Length; i++)
{
if (cards[i].GameNum == 14)
{
result.Add(cards[i]);
}
}
if (result.Count >= 3)
{
return result;
}
return null;
}
static bool IsSiDai3(TCardInfoPdkF[] selectCards, bool isPaiBuGou, out byte gameNum)
{
gameNum = 0;
if (selectCards == null || selectCards.Length < 5 || selectCards.Length > 7) return false;
if (isPaiBuGou && selectCards.Length != 7) return false;
var b = PokerLogic.GetPlayZhaDan(selectCards, out var cards);
if (!b) return b;
gameNum = cards[0].GameNum;
return true;
}
/// <summary>
/// 是否是四带二
/// </summary>
/// <param name="selectCards"></param>
/// <param name="isPaiBuGou">true牌够false牌不够</param>
/// <returns>true是 false不是</returns>
#pragma warning disable CS1573 // 参数在 XML 注释中没有匹配的 param 标记(但其他参数有)
static bool IsSiDai2(TCardInfoPdkF[] selectCards, bool isPaiBuGou, out byte gameNum)
#pragma warning restore CS1573 // 参数在 XML 注释中没有匹配的 param 标记(但其他参数有)
{
gameNum = 0;
if (selectCards == null || selectCards.Length < 5 || selectCards.Length > 6) return false;
if (isPaiBuGou && selectCards.Length != 6) return false;
var b = PokerLogic.GetPlayZhaDan(selectCards, out var cards);
if (!b) return b;
gameNum = cards[0].GameNum;
return true;
}
/// <summary>
/// 判断是否是炸弹
/// </summary>
/// <param name="selectCards"></param>
/// <param name="isCheckPaiCount">是否要校验牌的张数对不对</param>
/// <returns></returns>
static bool IsZhaDan(TCardInfoPdkF[] selectCards, bool isCheckPaiCount = true)
{
if (selectCards == null || selectCards.Length < 4) return false;
int gameNum = 0;
foreach (var item in selectCards)
{
if (gameNum == 0)
{
gameNum = item.GameNum;
continue;
}
if (gameNum != item.GameNum)
{
//炸弹的牌不是一样的牌
return false;
}
}
var b = PokerLogic.GetPlayZhaDan(selectCards, out var cards);
if (!b) return b;
if (isCheckPaiCount)
{
//校验返回的炸弹牌数量和传入的牌数量是不是一样多
return selectCards.Length == cards.Count;
}
return true;
}
/// <summary>
/// 判断是否有炸弹
/// </summary>
/// <param name="selectCards"></param>
/// <param name="aaaIsBomb">AAA是否是炸弹 true是 false不是</param>
/// <returns></returns>
public static bool IsHaveBomb(TCardInfoPdkF[] selectCards, bool aaaIsBomb)
{
if (selectCards == null || selectCards.Length < 3) return false;
if (!aaaIsBomb && selectCards.Length < 4) return false;
Dictionary<int, int> dic = new Dictionary<int, int>();
for (int i = 0; i < selectCards.Length; i++)
{
if (dic.ContainsKey(selectCards[i].GameNum))
{
dic[selectCards[i].GameNum]++;
}
else
{
dic[selectCards[i].GameNum] = 1;
}
}
foreach (var item in dic)
{
if (aaaIsBomb && item.Key == 14 && item.Value == 3) return true;
if (item.Value >= 4) return true;
}
return false;
}
}
}

View File

@ -0,0 +1,162 @@
using System.Text;
namespace GameFix.PaoDeKuaiF
{
/// <summary>
/// 跑得快玩法规则
/// </summary>
public class PdkRule
{
/// <summary>
/// 经典玩法 (必压) false不是 true是
/// 经典玩法16张玩法一副牌去掉大小王、三个2保留黑桃2和黑桃 A 共48张每人16张
/// </summary>
public bool JingDianWanFa;
/// <summary>
/// 是否必压 true必压 false不必压
/// </summary>
public bool BiYa;
/// <summary>
/// 15张玩法 false不是 true是
/// 15张玩法有大必压一副牌去掉大小王、三个2保留黑桃2和三个A保留黑桃 A 去掉一个K共45张每人15张
/// </summary>
public bool Zhang15;
/// <summary>
/// 关牌不必压false不是 true是
/// 一副牌去掉大小王、三个2保留黑桃2和黑桃 A 共48张每人16张
/// </summary>
public bool GuanPai;
/// <summary>
/// 首局黑桃3玩家先出下局赢家先出。false不是 true是
/// </summary>
public bool ShouJu3;
//注意2个人都没有黑桃3的情况下那就从小到大找黑桃的比如没有黑桃3就找黑桃4.看谁有就随先出
/// <summary>
/// 每局黑桃3先出。 如果是2个玩家玩
/// </summary>
public bool MeiJu3;
/// <summary>
/// 4带3张 false不是 true是 AAA只能带2张
/// </summary>
public bool SiDai3;
/// <summary>
/// 4带两张 false不是 true是 AAA只能带2张
/// </summary>
public bool SiDai2;
/// <summary>
/// 显示剩余牌数 false不是 true是
/// </summary>
public bool XianShenYuPai;
/// <summary>
/// 红桃十扎鸟 false不是 true是
/// 有红桃十玩家手牌输赢分翻倍
/// </summary>
public bool HongTao10ZhaNiao;
/// <summary>
/// 炸弹加分 true加10分 false不加分
/// </summary>
public bool ZhaDanDeFen;
/// <summary>
/// 3张A是不是炸弹 true是 false不是
/// </summary>
public bool AAAIsZhaDan;
/// <summary>
/// 下家报单,上家有压必压 true是 false不是。
/// 如果勾选了,那么上家要出最大的单张
/// </summary>
public bool XiaJiaBaoDan;
/// <summary>
/// 包庄 true包庄 false不包庄
/// 玩家选择包庄,打完不能让其他玩家出牌,关了算春天,输赢分*2如果让其他玩家出牌了包庄失败输赢分也要*2。
/// 如果有2个闲家包庄庄家的下家为包庄玩家。如果一庄一闲。那庄家为包庄。
/// </summary>
public bool BaoZhuang;
/// <summary>
/// 托管的时间 0不托管 1超过1分钟托管 3超过3分钟托管 5超过5分钟托管
/// </summary>
public int TuoGuanNum;
/// <summary>
/// 首局黑桃三首次必出
/// </summary>
public bool HeiTao3BiChu;
public override string ToString()
{
StringBuilder sb = new StringBuilder();
if (JingDianWanFa)
{
sb.Append("经典玩法, ");
}
if (Zhang15)
{
sb.Append("15张玩法, ");
}
if (GuanPai)
{
sb.Append("关牌玩法, ");
}
if (MeiJu3)
{
sb.Append("每局黑桃3先出, ");
}
if (ShouJu3)
{
sb.Append("首局黑桃3先出, ");
}
if (SiDai3)
{
sb.Append("四带三, ");
}
if (SiDai2)
{
sb.Append("四带二, ");
}
if (HongTao10ZhaNiao)
{
sb.Append("红桃10扎鸟, ");
}
if (ZhaDanDeFen)
{
sb.Append("炸弹加10, ");
}
if (AAAIsZhaDan)
{
sb.Append("3A为最大炸弹, ");
}
if (BaoZhuang)
{
sb.Append("包庄, ");
}
sb.Append(BiYa ? "必压, " : "不必压, ");
if (XianShenYuPai)
{
sb.Append("显示剩余牌数, ");
}
if (XiaJiaBaoDan)
{
sb.Append("下家报单,上家有压必压, ");
}
if (HeiTao3BiChu)
{
sb.Append("首局黑桃三首次必出 ");
}
return sb.ToString();
}
}
}

View File

@ -0,0 +1,39 @@
using GlobalSever.Form;
using Server;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace PdkFriendServer.GlobalManager
{
public class GameServerProxy : ServerProxy
{
//游戏服务器名称,显示用的标题
protected override ServerUtilFactory CreateUtilFactory()
{
return new MyFactory();
}
public GameServerProxy() : base()
{
ServerName = "跑得快朋友房";
}
/// <summary>
///
/// </summary>
/// <returns></returns>
public override ServerTable[] GetServerTable()
{
return new ServerTable[]{
new GameControl(this),
new GameTestTable(this)
//, new DaZhaForm(this)
};
}
}
}

View File

@ -0,0 +1,20 @@
using Server;
using GameMessage.PaoDeKuaiF;
namespace PdkFriendServer.GlobalManager
{
public class GameSeverManager : GameBase
{
protected override GameUtilFactory CreateFactory()
{
return new PdkFactory();
}
protected override void PreLoadMessagePack()
{
PdkGamePack pack = new PdkGamePack();
byte[] data = MessageHelper.MessagePackSerialize(pack);
pack = MessageHelper.MessagePackDeserialize<PdkGamePack>(data);
}
}
}

View File

@ -0,0 +1,41 @@
using Server;
using Server.Config;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
namespace PdkFriendServer.GlobalManager
{
public class MyFactory : ServerUtilFactory
{
public override Server.GlobalManager GetGlobalManager()
{
return new GameSeverManager();
}
public override object Produce(string ObjectName)
{
switch (ObjectName)
{
case "GameInfo":
return new GameSerInfo();
case "castleInfo":
return new CastleSerInfo();
case "tingInfo":
return new TingSerInfo();
case "deskInfo":
return new DeskSerInfo();
}
return null;
}
public override Server.GlobalManager.MessageProcessor CreateMessageProcessor()
{
return new GameBase.GameMessageProcessor();
}
}
}

View File

@ -0,0 +1,17 @@
using Server;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace PdkFriendServer.GlobalManager
{
public class PdkFactory : GameUtilFactory
{
public override GameDo GetGameDo(Desk desk)
{
return new PdkGameDo(desk);
}
}
}

View File

@ -0,0 +1,274 @@
/********************************
*
* 作者:徐高庆
* 创建时间: 2024年5月27日15:05:28
*
********************************/
using GameData;
using MrWu.Debug;
using PdkFriendServer.Logic;
using Server;
using Server.Pack;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MessagePack;
using GameMessage.PaoDeKuaiF;
using Server.Core;
using Server.Data;
using MessageHelper = Server.MessageHelper;
namespace PdkFriendServer.GlobalManager
{
public class PdkGameDo : GameDo
{
/// <summary>
/// 跑得快朋友房主要逻辑
/// </summary>
PdkGameMain Main;
/// <summary>
/// 计时器
/// </summary>
int timeNum;
public Desk desk = null;
public PdkGameDo(Desk desk) : base(desk)
{
Main = new PdkGameMain(this);
this.desk = desk;
}
public override void DoZyxPack(GamePack data)
{
PdkLogicInfo logicInfo;
if (data.IsBinary)
{
logicInfo = MessagePackHelper.Deserialize<PdkLogicInfo>(data.Data);
}
else
{
if (data.JsonData.Length < 10)
{ //托管包
byte[] tgData = JsonPack.GetData<byte[]>(data.JsonData);
Debug.Info("收到托管包" + data.JsonData.Length);
if (tgData[1] == 0)
{
Main.GamePack.Info.PlayTuoGauan[tgData[0]] = tgData[1];
desk[tgData[0]].SetDeposit( tgData[1] == 1 ? true : false);
}
return;
}
logicInfo = JsonPack.GetData<PdkLogicInfo>(data.JsonData);
}
var b = Main.CheckPack(logicInfo);
if (!b)
{
Debug.Warning("客户端包内容检查不过。收包错误");
return;
}
//正式连客户端以后要屏蔽这些代码。return
switch (Main.GamePack.Info.GameZT) //只要客户端输入的值
{
case 3://包庄
Main.GamePack.Info.BaoZhuang[logicInfo.WhoPlay - 1] = logicInfo.BaoZhuang[logicInfo.WhoPlay - 1];
break;
case 4: //打牌
Main.GamePack.Info.ActivePlayCard = logicInfo.ActivePlayCard;
Main.TimeNum = 0; //重置time计时器
break;
}
Debug.Info("收到子游戏包GameDo!");
this.Main.GameDo();
}
public override void StartWar()
{
timeNum = 0;
base.StartWar();
Main.GameStart();
}
public void SendGamePack()
{
var str = JsonPack.GetJson(Main.GamePack);
int len = desk.Count;
PlayerDataAsyc tmppl;
byte[] data = MessageHelper.MessagePackSerialize(this.Main.GamePack);
for (int i = 0; i < Main.GamePack.Info.PlayNum; i++)
{
tmppl = desk[i];
if (tmppl==null||tmppl.isRobot)continue;
if (tmppl.ClientVer > 46)
{
ClearOtherCard(tmppl.seat, data,false);
}
else
{
byte[] datastr= Encoding.UTF8.GetBytes(str);
ClearOtherCard(tmppl.seat, datastr,true);
}
}
SaveGameData(data);
SaveHuiFang(0, str);
}
/// <summary>
/// 发包前清空不是自己手里的牌
/// </summary>
/// <param name="pos"></param>
/// <param name="packData"></param>
void ClearOtherCard(int pos, byte[] packData,bool isOld)
{
try
{
if (Main.GamePack.Info.OverPos > 0)
{//如果是游戏结束的话就不清空玩家牌了,因为最后要亮玩家手牌
SendPack(pos, packData);
return;
}
var pack = isOld ? JsonPack.GetData<PdkGamePack>(Encoding.UTF8.GetString(packData))
: MessagePackHelper.Deserialize<PdkGamePack>(packData);
for (int i = 0; i < Main.GamePack.Info.PlayNum; i++)
{
if (i == pos) continue;
for (int j = 0; j < pack.CardPack.Cards[i].CardInfos.Length; j++)
{
if (pack.CardPack.Cards[i].CardInfos[j].GameState == 0) continue; //打下去的牌不清空
pack.CardPack.Cards[i].CardInfos[j] = new TCardInfoPdkF();
}
}
//var str = JsonPack.GetJson(pack);
SendPack(pos, packData);
}
catch (Exception e)
{
Debug.Error($"发包前清空不是自己手里的牌,msg:{e.Message} code:{e.StackTrace}");
SendPack(pos, packData);
}
}
public void SaveGameData(byte[] data)
{
SaveData(data);
}
public override void LoadMem(byte[] data,bool isOld)
{
Main.SetFriendGz();
if (isOld)
{
Main.GamePack = JsonPack.GetData<PdkGamePack>(Encoding.UTF8.GetString(data));
}
else
{
Main.GamePack = MessageHelper.MessagePackDeserialize<PdkGamePack>(data);
}
Main.LoadInit();
}
public override void LoadMemSuccess()
{
Main.SetOperation();
}
public void GameOver()
{
for (int i = 0; i < Main.GamePack.Info.PlayNum; i++)
{
var num = Main.GamePack.Info.Score[i];
SetPlayer(i, 8, num, string.Empty);
}
SendGamePack();
WarOver();
}
public override void Reconnect(int seat)
{
if (seat < 0)
{
int len = desk.Count;
PlayerDataAsyc tmppl;
byte[] data = MessagePackHelper.Serialize(this.Main.GamePack);
for (int i = 0; i < len; i++)
{
tmppl= desk[i];
if(tmppl==null||tmppl.isRobot)continue;
if (desk[seat].ClientVer > 46)
{
// 新客户端 MessagePack
ClearOtherCard(seat, data,false);
}
else
{
// 老的客户端 Encding
byte[] datastr= Encoding.UTF8.GetBytes(JsonPack.GetJson(this.Main.GamePack));
ClearOtherCard(seat, datastr,true);
}
}
}else if(seat < desk.PlayerCnt)
{
if (desk[seat] == null)
{
Debug.Error("逻辑错误!------{0},PlayerCnt:{1}", seat, desk.PlayerCnt);
return;
}
byte[] data = MessagePackHelper.Serialize(this.Main.GamePack);
if (!desk[seat].isRobot)
{
if (desk[seat].ClientVer > 46)
{
// 新客户端 MessagePack
ClearOtherCard(seat, data,false);
}
else
{
// 老的客户端 Encding
byte[] datastr= Encoding.UTF8.GetBytes(JsonPack.GetJson(this.Main.GamePack));
ClearOtherCard(seat, datastr,true);
}
}
}
else
{
Debug.Warning("发包位置大于桌子人数!" + seat + "," + desk.PlayerCnt);
}
}
public override void OnTime(int interval)
{
//200毫秒一次一秒执行5次
timeNum++;
if (timeNum >= 5)
{
timeNum = 0;
this.Main.DoTime();
}
}
public override void WarOver()
{
desk.WarOver();
isFighting = false;
}
public Desk GetDesk()
{
return this.desk;
}
}
}

View File

@ -0,0 +1,814 @@
using GameData;
using MrWu.Debug;
using PdkFriendServer.GlobalManager;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using GameMessage.PaoDeKuaiF;
using GameFix.PaoDeKuaiF;
using GameMessage;
using Server.Data;
namespace PdkFriendServer.Logic
{
/// <summary>
/// 跑得快朋友房主逻辑
/// </summary>
public partial class PdkGameMain
{
/// <summary>
/// 游戏主包
/// </summary>
public PdkGamePack GamePack;
/// <summary>
/// 服务器本地内存
/// </summary>
public LogicMemory logicMemory;
/// <summary>
/// 规则
/// </summary>
public PdkRule Rule;
/// <summary>
/// 桌子对象
/// </summary>
public PdkGameDo DeskGameDo = null;
public PdkGameMain(PdkGameDo _gamedo)
{
this.DeskGameDo = _gamedo;
this.GamePack = new PdkGamePack();
}
/// <summary>
/// 游戏开始
/// </summary>
public void GameStart()
{
byte shangyou = 0; //上游位置从1开始
byte overJu = (byte)(this.DeskGameDo == null ? 0 : DeskGameDo.GetDeskInt(8)); //打完了几局0就是一局都没有打完也就是首局
shangyou = GamePack.Info.OverPos;
var tg = GamePack.Info.PlayTuoGauan;
GamePack = new PdkGamePack();
if (this.DeskGameDo != null)
{
SetFriendGz();
GamePack.Init(GamePack.Info.PlayNum);
}
else
{ //测试的规则
GamePack.Init(3);
GamePack.Info.PlayNum = 3;
//设置玩法规则
Rule = new PdkRule();
Rule.GuanPai = true; //经典玩法
Rule.BiYa = true;//不必压
Rule.ShouJu3 = true;
Rule.SiDai3 = true;
Rule.BaoZhuang = true;
Rule.ZhaDanDeFen = true;
}
LoadInit();
if (overJu == 0)
{
logicMemory.BombCount = 0;
}
logicMemory.WarCount = overJu;
logicMemory.ShangYou = shangyou;
if (overJu != 0)
{
GamePack.Info.PlayTuoGauan = tg;
}
GamePack.Info.GameZT = 2;
Log(Rule.ToString());
//this.GameFaPai(); //屏蔽掉让dotime驱动流程玩下周
}
/// <summary>
/// 设置规则自动准备时间
/// </summary>
void SetAutoReadTime()
{
if (this.Rule.TuoGuanNum <= 0) return;
if (this.DeskGameDo == null) return;
if (this.DeskGameDo.desk == null) return;
if (this.DeskGameDo.desk.deskinfo == null) return;
if (this.DeskGameDo.desk.deskinfo.rule == null) return;
if (this.DeskGameDo.desk.deskinfo.rule.RuleEx == null) return;
// if (!this.DeskGameDo.desk.deskinfo.rule.RuleEx.DepositAutoDissolve) return;
if (this.DeskGameDo.desk.deskinfo.rule.RuleEx.AutoDeposit > 0) return;
this.DeskGameDo.desk.deskinfo.rule.RuleEx.AutoDeposit = this.Rule.TuoGuanNum * 60;
}
/// <summary>
/// 计时器 1秒钟执行一次
/// </summary>
public void DoTime()
{
SetAutoReadTime();
switch (GamePack.Info.GameZT)
{
//case 1:
// GameStart();
// break;
case 2:
GameFaPai();
break;
case 3:
BaoZhuangTuoGuan();
break;
case 4:
//if (Rule.TuoGuanNum > 0)
//{//需要托管
DaPaiTuoGuan();
//}
//玩家先手,并且是最后一张牌,就自动帮玩家出牌
if (GamePack.Info.MaxPlayCard.GameNum <= 0)
{
var cards = GamePack.CardPack.Cards[GamePack.Info.WhoPlay - 1].CardInfos.Where(x => x.GameState == 1).ToArray();
var b = PdkCardAlgorithm.GetOutCard(cards, cards, Rule, out var payCard);
var zhad = PdkCardAlgorithm.IsHaveBomb(cards, Rule.AAAIsZhaDan);
if (b && payCard.Ids.Length == cards.Length && payCard.Type != CardType1.SiDai2 && payCard.Type != CardType1.SiDai3 && !zhad)
{
payCard.Pos = (byte)GamePack.Info.WhoPlay;
GamePack.Info.ActivePlayCard = payCard;
Log($"最后一张牌,就自动帮玩家出牌 who:{GamePack.Info.WhoPlay}先出 ,托管出的牌:{payCard}");
GamePack.Info.ActivePlayCard = payCard;
Debug.Info("最后一手GameDo");
GameDo();
}
}
break;
case 5:
if (this.TimeNum >= 2)
{
GameOver();
}
break;
default:
// Log("DoTime default ");
break;
}
TimeNum++;
}
/// <summary>
/// 游戏发牌
/// </summary>
public void GameFaPai()
{
byte bc = 0; //计算这局的炸弹个数
for (int i = 0; i < 20; i++)
{
if (i > 0)
{
Log($"发牌i:{i} bnum:{bc} lc:{logicMemory.BombCount}", DebugLevel.ImportantLog);
}
InitCard();
bc = 0;
bool b = false;
for (int j = 0; j < GamePack.Info.PlayNum; j++)
{
byte bnum = CalcPlayBombRule(j);
Log($"玩家:{j},bombCount:{bnum}");
//if (bnum > 1) //单个人一手牌不能有超过2个炸弹
//{
// bc += (byte)bnum;
// break;
//}
if (bnum > 0)
{
bc += bnum;
}
}
if (logicMemory.BombCount + bc <= 1)
{
logicMemory.BombCount += bc;
b = true;
}
if (b)
{
break;
}
}
CheckFeiJi();
if (Rule.HongTao10ZhaNiao)
{ //红桃十扎鸟
GamePack.Info.HongTaoShiPos = GetHongTaoShiPos();
}
if (Rule.MeiJu3)
{ //每局黑桃3出
GamePack.Info.FistPlay = GetHeiTao3Pos();
Log($"第一个出牌位置:{GamePack.Info.FistPlay}");
}
else if (Rule.ShouJu3)
{ //首局黑桃三先出,下局赢家出
GamePack.Info.FistPlay = logicMemory.WarCount == 0 ? GetHeiTao3Pos() : logicMemory.ShangYou;
Log($"第一个出牌位置:{GamePack.Info.FistPlay},开始次数:{logicMemory.WarCount},上游玩家:{logicMemory.ShangYou}");
}
GamePack.Info.WhoPlay = GamePack.Info.FistPlay;
GamePack.Info.GameZT = (byte)(Rule.BaoZhuang ? 3 : 4);
TimeNum = 0;
SendPack();
}
/// <summary>
/// 包庄流程
/// </summary>
public void GameBaoZhuang()
{
int bcount = 0;//包庄的人数
byte[] pos = new byte[GamePack.Info.PlayNum]; //包庄人的位置
bool zhuangB = false;
if (GamePack.Info.BaoZhuang[GamePack.Info.FistPlay - 1] == 1)
{ //庄家包庄了,直接进入下一流程
GamePack.Info.WhoPlay = GamePack.Info.FistPlay;
GamePack.Info.BaoPos = GamePack.Info.WhoPlay;
GamePack.Info.GameZT = 4; //进入打牌
SetFalseOperation();
SendPack();
return;
}
else
{
for (byte i = 0; i < GamePack.Info.PlayNum; i++)
{
if (GamePack.Info.BaoZhuang[i] == 0)
{
// GamePack.Info.WhoPlay = GetNextPos(GamePack.Info.WhoPlay);
SendPack();
return; //还有玩家没有操作,不处理流程
}
if (GamePack.Info.BaoZhuang[i] == 1)
{
pos[bcount] = (byte)(i + 1);
if (!zhuangB && pos[bcount] == GamePack.Info.FistPlay)
{
zhuangB = true;
}
bcount++;
}
}
}
if (bcount == 1)
{
GamePack.Info.WhoPlay = pos[0];
GamePack.Info.BaoPos = GamePack.Info.WhoPlay;
}
else if (bcount > 1)
{ //多个人包庄
if (zhuangB)
{//如果庄家包庄了,那么就是庄家为包庄
GamePack.Info.WhoPlay = GamePack.Info.FistPlay;
}
else
{ //如果没有包庄的话,那么靠近庄家的下一家为包庄玩家
byte npos = GetNextPos(GamePack.Info.FistPlay); //庄的下家
for (int j = 0; j < pos.Length; j++)
{
bool b = false;
for (byte i = 0; i < pos.Length; i++)
{
if (pos[i] == npos)
{
GamePack.Info.WhoPlay = pos[i];
b = true;
break;
}
}
if (!b)
{
npos = GetNextPos(npos);
}
else
{
break;
}
}
}
GamePack.Info.BaoPos = GamePack.Info.WhoPlay;
}
Log($"进入打牌play:{GamePack.Info.WhoPlay} ,包庄玩家的位置:{GamePack.Info.BaoPos}");
GamePack.Info.GameZT = 4; //进入打牌
SetFalseOperation();
SendPack();
}
/// <summary>
/// 打牌流程
/// </summary>
void GameDaPai()
{
Log("进入打牌流程,玩家出牌内容是:" + GamePack.Info.ActivePlayCard.ToString());
//如果玩家有出牌1修改牌内存2修改最大出牌信息
//记录炸弹计分
//判断一轮打完
//判断一局游戏打完
//转换控制权 一个玩家出完牌后
byte chupaiPos = 0;
if (GamePack.Info.ActivePlayCard.Type != CardType1.None)
{
chupaiPos = GamePack.Info.ActivePlayCard.Pos;
SetCardToOut(GamePack.Info.ActivePlayCard.Pos, GamePack.Info.ActivePlayCard.Ids);
if (Rule.ZhaDanDeFen && GamePack.Info.ActivePlayCard.Type == CardType1.ZhaDan)
{
//炸弹得分,并且出的是炸弹
/*炸弹+10打出炸弹+10分不勾选0分
在有大必压得玩法下,一轮中打出的炸弹只算当局最大的炸弹分,
不必压得玩法下,只要打出炸弹都算分*/
AddZhaDanCount(GamePack.Info.ActivePlayCard.Pos, 1);
// GamePack.Info.ZhaDans[GamePack.Info.ActivePlayCard.Pos - 1]++;
if (Rule.BiYa && GamePack.Info.MaxPlayCard.Type == CardType1.ZhaDan)
{
//把之前加的炸弹减回去。
//GamePack.Info.ZhaDans[GamePack.Info.MaxPlayCard.Pos - 1]--;
AddZhaDanCount(GamePack.Info.MaxPlayCard.Pos, -1);
}
}
GamePack.Info.MaxPlayCard = GamePack.Info.ActivePlayCard;
}
if (IsGameOver(chupaiPos))
{ //游戏是否结束
SendPack();
this.TimeNum = 0;
GamePack.Info.GameZT = 5;
// GameOver(); 修改为定时器驱动
return;
}
GamePack.Info.WhoPlay = GetNextPos(GamePack.Info.WhoPlay);
Debug.Info($"当前玩家:{GamePack.Info.WhoPlay},下一个出牌的人:{GamePack.Info.WhoPlay}");
if (GamePack.Info.WhoPlay == GamePack.Info.MaxPlayCard.Pos)
{ //一轮结束
Log("一轮结束");
GamePack.Info.MaxPlayCard.Pos = 0;
GamePack.Info.MaxPlayCard.GameNum = 0;
GamePack.Info.MaxPlayCard.Type = CardType1.None;
GamePack.Info.MaxPlayCard.Ids = null;
}
SendPack();
}
void GameOver()
{
Log($"进入结算 bao:{GamePack.Info.BaoPos},overpos:{GamePack.Info.OverPos}");
int count = 0;
if (Rule.JingDianWanFa || Rule.GuanPai)
{
count = 16;
}
if (Rule.Zhang15)
{
count = 15;
}
if (GamePack.Info.BaoPos > 0)
{ //有人包庄
var baoWin = GamePack.Info.BaoPos == GamePack.Info.OverPos;
Log($"baowin:{baoWin}");
for (int i = 0; i < GamePack.Info.PlayNum; i++)
{
if (i + 1 != GamePack.Info.BaoPos)
{ //先统计闲家
int bei = GamePack.Info.HongTaoShiPos == i + 1 || GamePack.Info.HongTaoShiPos == GamePack.Info.BaoPos ? 4 : 2; //红桃十扎鸟
GamePack.Info.Score[i] += (baoWin ? 0 - count * bei : count * bei);
}
}
}
else
{
for (int i = 0; i < GamePack.Info.PlayNum; i++)
{//先统计闲家
if (i + 1 != GamePack.Info.OverPos)
{
if (GamePack.Info.ShenYuCard[i] == 1) continue;
var bei = GamePack.Info.HongTaoShiPos == i + 1 || GamePack.Info.HongTaoShiPos == GamePack.Info.OverPos ? 2 : 1;//红桃十扎鸟
var num = GamePack.Info.ShenYuCard[i] == count ? count * 2 : GamePack.Info.ShenYuCard[i];
GamePack.Info.Score[i] += 0 - num * bei;
}
}
}
for (int i = 0; i < GamePack.Info.PlayNum; i++)
{
if (i + 1 == (GamePack.Info.BaoPos > 0 ? GamePack.Info.BaoPos : GamePack.Info.OverPos))
{ //统计庄家,把闲家的都加起来就是庄家的输赢
for (int j = 0; j < GamePack.Info.PlayNum; j++)
{
if (j == i) continue;
GamePack.Info.Score[i] -= GamePack.Info.Score[j];
}
}
}
for (int i = 0; i < GamePack.Info.PlayNum; i++)
{
if (GamePack.Info.ZhaDans[i] != 0)
{
GamePack.Info.Score[i] += (GamePack.Info.ZhaDans[i] * 10);
}
}
//处理托管罚分
var fafen = GetTuoGuanFaFen();
if (fafen > 0)
{
var tgPos = GetTuoGuanPlay();
if (tgPos >= 0)
{ //有玩家托管
//int fen = fafen / (GamePack.Info.PlayNum - 1);
for (int i = 0; i < GamePack.Info.PlayNum; i++)
{
if (i == tgPos)
{
GamePack.Info.Score[i] -= (fafen * (GamePack.Info.PlayNum - 1));
}
else
{
GamePack.Info.Score[i] += fafen;
}
}
}
}
#if DEBUG
for (int i = 0; i < GamePack.Info.PlayNum; i++)
{
Log($"玩家:{(i + 1)} ,输赢:{GamePack.Info.Score[i]}");
}
#endif
if (DeskGameDo != null)
{
DeskGameDo.GameOver();
}
}
/// <summary>
/// 是否托管罚分
/// </summary>
/// <returns>0不罚分 </returns>
int GetTuoGuanFaFen()
{
if (this.DeskGameDo == null || this.DeskGameDo.desk == null || this.DeskGameDo.desk.deskinfo == null || this.DeskGameDo.desk.deskinfo.rule == null ||
this.DeskGameDo.desk.deskinfo.rule.RuleEx == null) return 0;
return this.DeskGameDo.desk.deskinfo.rule.RuleEx.DepositAutoDissolve ? this.DeskGameDo.desk.deskinfo.rule.RuleEx.OutLinePenaltyPoint : 0;
}
/// <summary>
/// 找打托管的玩家
/// </summary>
/// <returns>从0开始 -1未找到</returns>
int GetTuoGuanPlay()
{
return DeskGameDo.GetPlayerFirstDepositSeat();
//var desk = DeskGameDo.GetDesk();
//for (int i = 0; i < GamePack.Info.PlayNum; i++)
//{
// if (desk[i] != null && desk[i].isDePosit)
// {//找到在 托管的玩家
// return i;
// }
//}
//return -1;
}
/// <summary>
/// 游戏发包,发全包
/// </summary>
void SendPack()
{
Log($"whoPlay:{GamePack.Info.WhoPlay}");
if (DeskGameDo == null)
{
var str = JsonPack.GetJson(this.GamePack);
File.WriteAllText(@"C:\Users\Administrator\Desktop\temp\gamepack.txt", str);
var path = $@"C:\Users\Administrator\Desktop\temp\test\gamepack{DateTime.Now.ToString("yyyy-MM-dd-HH-mm-ss-fff")}.txt";
Log("保存文件:" + path);
File.WriteAllText(path, str);
WaitWanJiaShuRu(); //等玩家输入。模拟玩家打牌
}
else
{
SetOperation();
DeskGameDo.SendGamePack();
}
}
void SetFalseOperation()
{
for (int i = 0; i < GamePack.Info.PlayNum; i++)
{
this.SetWaitOperation(i, false);
}
}
public void SetOperation()
{
for (int i = 0; i < GamePack.Info.PlayNum; i++)
{
var pl = this.DeskGameDo.desk[i];
if (pl != null)
{
GamePack.Info.PlayTuoGauan[i] = (byte)(pl.isDePosit ? 1 : 0);
}
bool b = false; //包庄流程是同时进行的
if (GamePack.Info.GameZT == 3)
{
b = GamePack.Info.BaoZhuang[i] == 0;
}
this.SetWaitOperation(i, GamePack.Info.GameZT == 3 ? b : i + 1 == GamePack.Info.WhoPlay);
}
}
/// <summary>
/// 设置玩家的操作权
/// </summary>
/// <param name="seat">下标从0开始</param>
/// <param name="waitOperation"></param>
public void SetWaitOperation(int seat, bool waitOperation)
{
var desk = this.DeskGameDo.GetDesk();
if (seat < 0 || seat >= desk.PlayerCnt)
{
return;
}
var pl = desk[seat];
if (pl != null)
{
//之前不能操作,现在可以操作,重置托管时间
if (!pl.WaitOperation && waitOperation)
{
pl.AutoDepositTime = 0;
}
pl.WaitOperation = waitOperation;
}
}
/// <summary>
/// 检查包内容是否合法
/// </summary>
/// <param name="pack"></param>
/// <returns></returns>
public bool CheckPack(PdkLogicInfo pack)
{
if (pack.WhoPlay != GamePack.Info.WhoPlay && GamePack.Info.GameZT > 3) return false;
switch (GamePack.Info.GameZT)
{
case 3: //包庄 只能输入1和2
return pack.BaoZhuang[pack.WhoPlay - 1] == 1 || pack.BaoZhuang[pack.WhoPlay - 1] == 2;
case 4:
if (pack.WhoPlay != pack.ActivePlayCard.Pos)
{
Debug.Error($"who:{pack.WhoPlay},apos:{pack.ActivePlayCard}");
return false;
}
return CheckChuPai(pack.ActivePlayCard);
}
return true;
}
public void GameDo()
{
switch (GamePack.Info.GameZT)
{
//case 1:
// GameStart();
// break;
case 2:
GameFaPai();
break;
case 3:
GameBaoZhuang();
break;
case 4:
GameDaPai();
break;
case 5:
GameOver();
break;
default:
Log("default GameDo game over");
break;
}
}
/// <summary>
/// 等待玩家输入
/// </summary>
void WaitWanJiaShuRu()
{
if (DeskGameDo != null) return;
//正式连客户端以后要屏蔽这些代码。return
string str = "";
byte num = 0;
switch (GamePack.Info.GameZT)
{
case 3://包庄流程只能输入1和2
Log("包庄操作 pos:" + GamePack.Info.WhoPlay);
while (true)
{
str = Console.ReadLine();
Log(str);
var ss = str.Split(',');
byte.TryParse(ss[0], out var pos);
byte.TryParse(ss[1], out num);
GamePack.Info.WhoPlay = pos;
GamePack.Info.BaoZhuang[pos - 1] = num;
if (CheckPack(GamePack.Info))
{
break; //如果包输入正确就跳走
}
else
{
Log("检测不合格,输入非法值");
}
}
break;
case 4: //打牌流程
Log("打牌操作 pos:" + GamePack.Info.WhoPlay);
while (true)
{
str = Console.ReadLine(); //逗号分隔
var ss = str.Split(',');
if (ss.Length <= 0) continue;
Log(str);
var selectCards = GamePack.CardPack.Cards[GamePack.Info.WhoPlay - 1].CardInfos.Where(x => ss.Any(s => s == x.ID.ToString())).ToArray();
PlayOutCardPdkF payCard;
if (selectCards == null || selectCards.Length <= 0) //不要
{
payCard = new PlayOutCardPdkF();
payCard.Pos = GamePack.Info.WhoPlay;
payCard.Type = CardType1.None;
GamePack.Info.ActivePlayCard = payCard;
if (CheckPack(GamePack.Info))
{
break; //如果包输入正确就跳走
}
else
{
Log("检测不合格,输入非法值");
}
}
else if (PdkCardAlgorithm.GetOutCard(selectCards,
GamePack.CardPack.Cards[GamePack.Info.WhoPlay - 1].CardInfos.Where(x => x.GameState == 1).ToArray(),
this.Rule, out payCard))
{
payCard.Pos = GamePack.Info.WhoPlay;
GamePack.Info.ActivePlayCard = payCard;
if (CheckPack(GamePack.Info))
{
break; //如果包输入正确就跳走
}
else
{
Log("检测不合格,输入非法值");
}
}
else
{
Log("输入的牌不符合规则,不能出下去");
}
}
break;
case 6:
//GameOver();
break;
}
}
void textxxxx()
{
// GameStart();
// GameFaPai();
//PlayOutCard output = new PlayOutCard();
//output.Pos = 1; output.Type = CardType.LianDui;
//output.GameNum = 9;
//output.Ids = new byte[6];
//TCardInfo[] shoupai = new TCardInfo[16];
//shoupai[0] = new TCardInfo() { ID = 1, GameNum = 14, Flower = 1, Num = 14, Score = 0, GameOwer = 1, GameState = 1 };
//shoupai[1] = new TCardInfo() { ID = 27, GameNum = 14, Flower = 3, Num = 14, Score = 0, GameOwer = 1, GameState = 1 };
//shoupai[2] = new TCardInfo() { ID = 26, GameNum = 13, Flower = 2, Num = 13, Score = 0, GameOwer = 1, GameState = 1 };
//shoupai[3] = new TCardInfo() { ID = 25, GameNum = 12, Flower = 2, Num = 12, Score = 0, GameOwer = 1, GameState = 1 };
//shoupai[4] = new TCardInfo() { ID = 38, GameNum = 12, Flower = 3, Num = 12, Score = 0, GameOwer = 1, GameState = 1 };
//shoupai[5] = new TCardInfo() { ID = 36, GameNum = 10, Flower = 3, Num = 10, Score = 0, GameOwer = 1, GameState = 1 };
//shoupai[6] = new TCardInfo() { ID = 49, GameNum = 10, Flower = 4, Num = 10, Score = 0, GameOwer = 1, GameState = 1 };
//shoupai[7] = new TCardInfo() { ID = 35, GameNum = 9, Flower = 3, Num = 9, Score = 0, GameOwer = 1, GameState = 1 };
//shoupai[8] = new TCardInfo() { ID = 48, GameNum = 9, Flower = 4, Num = 9, Score = 0, GameOwer = 1, GameState = 1 };
//shoupai[9] = new TCardInfo() { ID = 8, GameNum = 8, Flower = 1, Num = 8, Score = 0, GameOwer = 1, GameState = 1 };
//shoupai[10] = new TCardInfo() { ID = 34, GameNum = 8, Flower = 3, Num = 8, Score = 0, GameOwer = 1, GameState = 1 };
//shoupai[11] = new TCardInfo() { ID = 5, GameNum = 5, Flower = 1, Num = 5, Score = 0, GameOwer = 1, GameState = 1 };
//shoupai[12] = new TCardInfo() { ID = 18, GameNum = 5, Flower = 2, Num = 5, Score = 0, GameOwer = 1, GameState = 1 };
//shoupai[13] = new TCardInfo() { ID = 44, GameNum = 5, Flower = 4, Num = 5, Score = 0, GameOwer = 1, GameState = 1 };
//shoupai[14] = new TCardInfo() { ID = 16, GameNum = 3, Flower =2, Num = 3, Score = 0, GameOwer = 1, GameState = 1 };
//shoupai[15] = new TCardInfo() { ID = 29, GameNum = 3, Flower = 3, Num = 3, Score = 0, GameOwer = 1, GameState = 1 };
//var tishi = PdkCardAlgorithm.GetTipCard(output, shoupai, null);
//Console.WriteLine(tishi);
}
/// <summary>
/// 测试函数
/// </summary>
public void Test(string path = "")
{
//textxxxx();
//return;
if (File.Exists("output.txt"))
{
File.Delete("output.txt");
}
foreach (string file in Directory.GetFiles(@"C:\Users\Administrator\Desktop\temp\test"))
{
File.Delete(file);
}
bool b = true;
GamePack.Info.GameZT = 1;
if (!string.IsNullOrWhiteSpace(path))
{
GamePack = JsonPack.GetData<PdkGamePack>(File.ReadAllText(path));
}
while (b)
{
switch (GamePack.Info.GameZT)
{
case 1:
GameStart();
break;
case 2:
GameFaPai();
break;
case 3:
GameBaoZhuang();
break;
case 4:
GameDaPai();
break;
case 5:
GameOver();
GamePack.Info.GameZT = 11; //进入结束就结束
break;
default:
b = false;
Log("test over");
break;
}
}
}
void WriteToConsoleAndFile(StreamWriter writer, string message)
{
Console.WriteLine(message); // 写入控制台
writer.WriteLine(message); // 写入文件
}
public void Log(string msg, DebugLevel leve = DebugLevel.Info)
{
if (DeskGameDo == null)
{
using (StreamWriter writer = new StreamWriter("output.txt", true)) // 第二个参数为true表示追加到文件
{
WriteToConsoleAndFile(writer, $"[{DateTime.Now.ToString("G")}]:" + msg);
}
Thread.Sleep(1);
}
else
{
switch (leve)
{
case DebugLevel.Info:
Debug.Info(msg);
break;
case DebugLevel.Warning:
Debug.Warning(msg);
break;
case DebugLevel.ImportantLog:
Debug.ImportantLog(msg);
break;
case DebugLevel.Error:
Debug.Error(msg);
break;
case DebugLevel.Fatal:
Debug.Fatal(msg);
break;
default:
Debug.Info(msg);
break;
}
}
}
}
}

View File

@ -0,0 +1,348 @@
using ObjectModel.Tool;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using GameFix.Poker;
using GameMessage.PaoDeKuaiF;
using GameFix.PaoDeKuaiF;
namespace PdkFriendServer.Logic
{
public partial class PdkGameMain
{
/// <summary>
/// 随机值
/// </summary>
public readonly Random Random = new Random(unchecked((int)DateTime.UtcNow.Ticks));
/// <summary>
/// 发牌
/// </summary>
public void InitCard()
{
/*1、经典玩法(必压)、--经典玩法16张玩法一副牌去掉大小王、三个2保留黑桃2和黑桃 A 共48张每人16张
15张玩法(必压)、--15张玩法有大必压一副牌去掉大小王、三个2保留黑桃2和三个A保留黑桃 A 去掉一个K共45张每人15张
关牌(不必压) --一副牌去掉大小王、三个2保留黑桃2和黑桃 A 共48张每人16张*/
byte count = 0;//每个人分多少张牌
int del2 = 3; //删除2的张数
int delA = 1;//删除A的张数
int delK = 3;//删除K的张数
TCardInfoPdkF[] allCards = null; //初始化牌库
if (Rule.JingDianWanFa || Rule.GuanPai)
{
count = 16;
delK = 0;
allCards = new TCardInfoPdkF[48];
}
if (Rule.Zhang15)
{
delA = 3;
delK = 1;
count = 15;
allCards = new TCardInfoPdkF[45];
}
int idx = 0;
for (byte i = 1; i <= 52; i++)
{
PukeTool.ConvertCard(i, out var flower, out var num);
if (del2 > 0 && num == 2 && flower != 1)
{
del2--;
continue;
}
if (delA > 0 && num == 1 && flower != 1)
{
delA--;
continue;
}
if (delK > 0 && num == 13 && flower != 1)
{
delK--;
continue;
}
allCards[idx].ID = i;
allCards[idx].Flower = (byte)flower;
allCards[idx].Num = (byte)num;
allCards[idx].GameNum = (byte)(num == 1 ? 14 : num == 2 ? 16 : num);
allCards[idx].GameOwer = 0;
allCards[idx].Score = 0;
allCards[idx].GameState = 1;
idx++;
}
for (byte i = 1; i < GamePack.Info.PlayNum; i++)
{
PukeTool.ShuffleArray(ref allCards, Random);
}
idx = 0;
//给玩家发牌
int hei3Wei = -1;//黑桃三发牌的位置
if (logicMemory.WarCount == 0 && Rule.HeiTao3BiChu)
{//如果是首局而且是每局黑桃三必出,则第一局必须要发黑桃三
hei3Wei = Random.Next(0, GamePack.Info.PlayNum);
}
if (hei3Wei >= 0)
{ //要发黑桃3
List<TCardInfoPdkF> cards = allCards.ToList();
for (int i = 0; i < GamePack.Info.PlayNum; i++)
{
GamePack.CardPack.Cards[i].Init(count);
int j = 0;
while (j < count)
{
if (j == 0 && i == hei3Wei)
{
TCardInfoPdkF temp = cards.Find(x => x.GameNum == 3 && x.Flower == 1);
if (temp.ID > 0)
{
this.GamePack.CardPack.Cards[i].CardInfos[j] = temp;
cards.Remove(temp);
}
else
{ //如果没有找到说明黑桃3已经被别人拿走了就不找了。
this.GamePack.CardPack.Cards[i].CardInfos[j] = cards[0];
cards.RemoveAt(0);
}
}
else
{
this.GamePack.CardPack.Cards[i].CardInfos[j] = cards[0];
cards.RemoveAt(0);
}
j++;
}
GamePack.Info.ShenYuCard[i] = count;
}
}
else
{ //以前写法
for (int i = 0; i < GamePack.Info.PlayNum; i++)
{
GamePack.CardPack.Cards[i].Init(count);
for (int j = 0; j < count; j++)
{
this.GamePack.CardPack.Cards[i].CardInfos[j] = allCards[idx++];
}
GamePack.Info.ShenYuCard[i] = count;
}
}
for (int i = 0; i < GamePack.Info.PlayNum; i++)
{
SortWanJiaPaiByGameNum(i + 1);
#if DEBUG
if (this.DeskGameDo == null)
{
Log($"-------------{(i + 1)}开始-----------------------------");
for (int j = 0; j < this.GamePack.CardPack.Cards[i].CardInfos.Length; j++)
{
Log(this.GamePack.CardPack.Cards[i].CardInfos[j].ToString());
}
}
#endif
}
}
/// <summary>
/// 排序某个玩家手牌,按游戏中的大小排序
/// </summary>
/// <param name="pos">玩家位置从1开始</param>
void SortWanJiaPaiByGameNum(int pos)
{
if (pos <= 0 || pos > GamePack.Info.PlayNum) throw new Exception($"参数错误 pos:{pos}");
pos--;
Array.Sort(this.GamePack.CardPack.Cards[pos].CardInfos, (x, y) => (y.GameNum * 10 - y.Flower).CompareTo((x.GameNum * 10 - x.Flower)));
}
/// <summary>
/// 设置玩家出牌
/// </summary>
/// <param name="pos"></param>
/// <param name="ids"></param>
void SetCardToOut(int pos, byte[] ids)
{
if (ids == null || ids.Length <= 0) return;
if (pos <= 0 || pos > GamePack.Info.PlayNum) throw new Exception($"参数错误 pos:{pos}");
pos--;
GamePack.Info.ShenYuCard[pos] = (byte)(GamePack.Info.ShenYuCard[pos] - ids.Length);
foreach (var id in ids)
{
for (int i = 0; i < this.GamePack.CardPack.Cards[pos].CardInfos.Length; i++)
{
if (this.GamePack.CardPack.Cards[pos].CardInfos[i].ID == id)
{
this.GamePack.CardPack.Cards[pos].CardInfos[i].GameState = 0;
break;
}
}
}
#if DEBUG
Log($"---------------------{(pos + 1)}----- shengyu:{GamePack.Info.ShenYuCard[pos]}-------------");
//for (int i = 0; i < this.GamePack.CardPack.Cards[pos].CardInfos.Length; i++)
//{
// if (this.GamePack.CardPack.Cards[pos].CardInfos[i].GameState == 0) continue;
// Log(this.GamePack.CardPack.Cards[pos].CardInfos[i].ToString());
//}
#endif
}
/// <summary>
/// 根据牌的绝对Id返回牌的详细信息
/// </summary>
/// <param name="pos">玩家位置从1开始</param>
/// <param name="ids">牌的Id集合</param>
/// <returns></returns>
TCardInfoPdkF[] GetCardByIds(int pos, byte[] ids)
{
if (ids == null || ids.Length <= 0) return null;
if (pos <= 0 || pos > GamePack.Info.PlayNum) return null;
pos--;
return PokerLogic.GetCardByIds(GamePack.CardPack.Cards[pos].CardInfos, ids);
}
/// <summary>
/// 计算玩家炸弹个数
/// </summary>
/// <param name="pos">玩家位置从0开始</param>
/// <returns></returns>
byte CalcPlayBombRule(int pos)
{
if (pos < 0 || pos >= GamePack.Info.PlayNum) return 0;
Dictionary<int, int> dic = new Dictionary<int, int>();
foreach (var item in GamePack.CardPack.Cards[pos].CardInfos)
{
if (dic.ContainsKey(item.GameNum))
{
dic[item.GameNum]++;
}
else
{
dic[item.GameNum] = 1;
}
}
byte result = 0;
foreach (var item in dic)
{
if (item.Value <= 2) continue;
if (Rule.AAAIsZhaDan && item.Key == 14 && item.Value == 3)
{
result++;
continue;
}
if (item.Value == 4)
{
result++;
}
}
return result;
}
/// <summary>
/// 检测玩家的飞机如果有4连以上的飞机就需要换牌
/// </summary>
/// <param name="pos"></param>
/// <returns></returns>
void CheckFeiJi()
{
try
{
int pos = -1; //有4连飞机的位置
List<int> feiji = null;
for (int j = 0; j < GamePack.Info.PlayNum; j++)
{
feiji = GetFeiJiCount(GamePack.CardPack.Cards[j].CardInfos);
if (feiji != null && feiji.Count > 3)
{
pos = j;
Log($"飞机数量:{string.Join(",", feiji)},飞机位置:{pos + 1},房号:{this.DeskGameDo.desk.deskinfo.roomNum}", MrWu.Debug.DebugLevel.Warning);
break;
}
}
if (pos < 0) return;
for (int i = 0; i < GamePack.Info.PlayNum; i++)
{
if (i != pos)
{
int idx = -1;
for (int j = 0; j < GamePack.CardPack.Cards[pos].CardInfos.Length; j++)
{
if (GamePack.CardPack.Cards[pos].CardInfos[j].GameNum == feiji[2])
{
idx = j;
break;
}
}
if (idx < 0)
{
Log($"没有找到4连飞机的下标日{idx}", MrWu.Debug.DebugLevel.Warning);
return;
}
for (int i3 = 0; i3 < GamePack.CardPack.Cards[i].CardInfos.Length - 1; i3++)
{
//交换其中一张牌
TCardInfoPdkF temp = GamePack.CardPack.Cards[i].CardInfos[i3];
if (feiji.IndexOf(temp.GameNum) >= 0) continue; //换的牌不能是飞机的牌,要不容易重复和换出新的炸弹
Log($"换牌信息:{temp.GameNum}", MrWu.Debug.DebugLevel.Warning);
GamePack.CardPack.Cards[i].CardInfos[i3] = GamePack.CardPack.Cards[pos].CardInfos[idx];
GamePack.CardPack.Cards[pos].CardInfos[idx] = temp;
for (int i2 = 0; i2 < GamePack.Info.PlayNum; i2++)
{
SortWanJiaPaiByGameNum(i2 + 1);
}
return;
}
}
}
}
catch (Exception e)
{
Log($"CheckFeiJi msg:{e.Message}, code:{e.StackTrace}", MrWu.Debug.DebugLevel.Error);
}
}
/// <summary>
/// 获取一个玩家的飞机牌型
/// </summary>
/// <param name="selectCards">玩家手里的牌</param>
/// <returns>玩家的飞机集合</returns>
public static List<int> GetFeiJiCount(TCardInfoPdkF[] selectCards)
{
if (selectCards == null || selectCards.Length < 6) return null;
List<PokerLogic.XY> list = new List<PokerLogic.XY>();
foreach (var item in selectCards)
{
var t = list.Find(x => x.x == item.GameNum);
if (t != null)
{
t.y++;
}
else
{
list.Add(new PokerLogic.XY { x = item.GameNum, y = 1 });
}
}
int num = list.Count(x => x.y >= 3);
if (num < 2) return null;
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;
}
}
}

View File

@ -0,0 +1,468 @@
using GameData;
using MrWu.Debug;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using GameFix.Poker;
using GameFix.PaoDeKuaiF;
using GameMessage;
using GameMessage.PaoDeKuaiF;
namespace PdkFriendServer.Logic
{
public partial class PdkGameMain
{
/// <summary>
/// 获取黑桃3的位置如果都没有黑桃3那就取黑桃4
/// </summary>
/// <returns></returns>
byte GetHeiTao3Pos()
{
byte result = 0;
for (byte carId = 3; carId < 14; carId++)
{//从黑桃3开始找没有找到就依次往上查找
for (byte i = 0; i < GamePack.Info.PlayNum; i++)
{
for (int j = GamePack.CardPack.Cards[i].CardInfos.Length - 1; j >= 0; j--)
{
if (GamePack.CardPack.Cards[i].CardInfos[j].Flower != 1) continue;
if (GamePack.CardPack.Cards[i].CardInfos[j].GameNum > carId) break;
if (GamePack.CardPack.Cards[i].CardInfos[j].GameNum == carId)
{
result = (byte)(i + 1);
return result;
}
}
}
}
return result;
}
/// <summary>
/// 获取红桃十的玩家位置
/// </summary>
/// <returns>0没有玩家有红桃十 大于0就是改位置的玩家</returns>
byte GetHongTaoShiPos()
{
byte result = 0;
for (byte i = 0; i < GamePack.Info.PlayNum; i++)
{
for (int j = GamePack.CardPack.Cards[i].CardInfos.Length - 1; j >= 0; j--)
{
if (GamePack.CardPack.Cards[i].CardInfos[j].Flower != 2) continue;
if (GamePack.CardPack.Cards[i].CardInfos[j].GameNum == 10)
{
result = (byte)(i + 1);
return result;
}
}
}
return 0;
}
/// <summary>
/// 查找下一个玩家的位置
/// </summary>
/// <param name="pos"></param>
/// <returns></returns>
byte GetNextPos(byte pos)
{
if (pos <= 0) throw new Exception("参数错误" + pos);
byte result = (byte)(pos + 1);
if (result > GamePack.Info.PlayNum)
{
result = 1;
}
return result;
}
/// <summary>
/// 游戏是否结束
/// </summary>
/// <returns>true游戏结束 false游戏没有结束</returns>
bool IsGameOver(byte chupaoPos)
{
if (GamePack.Info.BaoPos > 0 && GamePack.Info.ShenYuCard[GamePack.Info.BaoPos - 1] == 0)
{
//包庄人的牌出完了,游戏结束
GamePack.Info.OverPos = GamePack.Info.BaoPos;
return true;
}
//如果是包庄的话,出牌的人
if (GamePack.Info.BaoPos > 0 && chupaoPos > 0)
{
var b = GamePack.Info.BaoPos != chupaoPos; //如果出牌的位置和包庄位置不一样。就说明被别人给压牌了,游戏结束
if (b)
{
GamePack.Info.OverPos = chupaoPos; //记录压他牌的人位置
}
return b;
}
for (int i = 0; i < GamePack.Info.PlayNum; i++)
{
if (GamePack.Info.ShenYuCard[i] <= 0)
{ //只要有一个玩家的牌出完就结束
GamePack.Info.OverPos = (byte)(i + 1);
return true;
}
}
return false;
}
/// <summary>
/// 检查出牌包内容
/// </summary>
/// <param name="pack"></param>
/// <returns></returns>
public bool CheckChuPai(PlayOutCardPdkF payCard)
{
if (payCard.Pos <= 0 || payCard.Pos > 3) return false;
if (PokerLogic.CheckSameId(payCard.Ids))
{
Log($"玩家出了相同ID的牌型{payCard}", DebugLevel.Error);
return false;
}
if (GamePack.Info.MaxPlayCard.GameNum == 0 && payCard.Type == CardType1.None) return false; //第一个出牌人不能出不要
if (GamePack.Info.MaxPlayCard.GameNum > 0 && payCard.Type == CardType1.None)
{
if (!Rule.BiYa && !Rule.XiaJiaBaoDan) return true; //不是必压的情况下,并且没有勾选下家报单,之前有人出牌,再出个不要可以出
//不必压,但是勾选下家报单,之前出的不是单张,这个时候可以出不要。
if (!Rule.BiYa && Rule.XiaJiaBaoDan && GamePack.Info.MaxPlayCard.Type != CardType1.DanZhang) return true;
if (!Rule.BiYa && Rule.XiaJiaBaoDan && GamePack.Info.ShenYuCard[GetNextPos(payCard.Pos) - 1] != 1) return true;
}
if (!CheckPaiIsInHand(payCard.Ids, payCard.Pos)) return false;
if (!Rule.AAAIsZhaDan && payCard.Type == CardType1.ZhaDan && payCard.GameNum == 14) return false; //3个A不是炸弹
if (!Rule.SiDai2 && payCard.Type == CardType1.SiDai2) return false;
if (!Rule.SiDai3 && payCard.Type == CardType1.SiDai3) return false;
//if (!Rule.BiYa && GamePack.Info.MaxPlayCard.GameNum > 0 && payCard.Type == CardType.None) return true; //如果之前有人出牌,再出个不要可以出
if ((Rule.BiYa ||
(Rule.XiaJiaBaoDan && GamePack.Info.MaxPlayCard.Type == CardType1.DanZhang && GamePack.Info.ShenYuCard[GetNextPos(payCard.Pos) - 1] == 1))
&& payCard.Type == CardType1.None)
{ //如果是必压,玩家出了不要,检查一下玩家有没有必上一家大的牌
return !PdkCardAlgorithm.CheckHaveBigger(GamePack.Info.MaxPlayCard, GamePack.CardPack.Cards[payCard.Pos - 1].CardInfos.Where(x => x.GameState == 1).ToArray(),
GamePack.CardPack.Cards[GamePack.Info.MaxPlayCard.Pos - 1].CardInfos, Rule.AAAIsZhaDan);
}
int count = GamePack.Info.ShenYuCard[payCard.Pos - 1];
//单张、对子、三带二、顺子、连对、飞机带翅膀、炸弹,四带三、四带二
if (payCard.Type == CardType1.SanDai2 && count >= 5 && payCard.Ids.Length < 5) return false;
if (payCard.Type == CardType1.SiDai3 && count >= 7 && payCard.Ids.Length < 7) return false;
if (payCard.Type == CardType1.SiDai2 && count >= 6 && payCard.Ids.Length < 6) return false;
if (payCard.Type == CardType1.FeiJi)
{//如果飞机的张数不够就返回false
if (count >= 10 && payCard.Ids.Length < 10) return false;
var sanzhang = PokerLogic.GetFeiJiCount(GetCardByIds(payCard.Pos, payCard.Ids));
var c = sanzhang * 3 + sanzhang * 2;
if (count >= c && payCard.Ids.Length < c) return false;
var maxSanZahng = PokerLogic.GetFeiJiCount(GetCardByIds(GamePack.Info.MaxPlayCard.Pos, GamePack.Info.MaxPlayCard.Ids));
if (sanzhang < maxSanZahng) return false;
}
if (GamePack.Info.MaxPlayCard.GameNum == 0)
{
//如果最大的出牌人是没有值的话,然后当前人不是出不要就可以出下去。
return payCard.Type != CardType1.None;
}
if (GamePack.Info.MaxPlayCard.Type == payCard.Type)
{
if (payCard.Type == CardType1.DanZhang || payCard.Type == CardType1.DuiZi || payCard.Type == CardType1.ShunZi || payCard.Type == CardType1.LianDui)
{
return payCard.Ids.Length == GamePack.Info.MaxPlayCard.Ids.Length && payCard.GameNum > GamePack.Info.MaxPlayCard.GameNum;
}
else
{
return payCard.GameNum > GamePack.Info.MaxPlayCard.GameNum;
}
}
else
{
if (GamePack.Info.MaxPlayCard.Type != CardType1.ZhaDan)
{
return payCard.Type == CardType1.ZhaDan;
}
}
return false;
}
/// <summary>
/// 检测牌是否都在玩家手上
/// </summary>
/// <param name="Ids">要检测的牌ID集合</param>
/// <param name="pos">要检测哪个玩家的手牌</param>
/// <returns>true都在手上 false没有在手上</returns>
bool CheckPaiIsInHand(byte[] Ids, int pos)
{
if (pos <= 0 || pos > GamePack.Info.PlayNum) return false;
if (Ids == null || Ids.Length <= 0) return true; //没有牌不检测
pos--;
int count = 0;
foreach (var id in Ids)
{
foreach (var item in GamePack.CardPack.Cards[pos].CardInfos)
{
if (item.ID == id && item.GameState == 1)
{
count++;
break;
}
}
}
return count == Ids.Length;
}
/// <summary>
/// 给某个玩家加炸弹,其他玩家减炸弹
/// </summary>
/// <param name="pos"></param>
/// <param name="num"></param>
void AddZhaDanCount(int pos, int num)
{
for (int i = 0; i < GamePack.Info.ZhaDans.Length; i++)
{
if (i + 1 == pos)
{
GamePack.Info.ZhaDans[i] += num * (GamePack.Info.ZhaDans.Length - 1);
}
else
{
GamePack.Info.ZhaDans[i] -= num;
}
}
}
/// <summary>
/// 设置朋友房规则
/// </summary>
public void SetFriendGz()
{
if (this.DeskGameDo == null) return;
var gz = this.DeskGameDo.GetRoomGz();
Rule = new PdkRule();
Rule.BiYa = true;//不必压
if (gz[0] == '0')
{
Rule.JingDianWanFa = true;
}
else if (gz[0] == '1')
{
Rule.Zhang15 = true;
}
else if (gz[0] == '2')
{
Rule.GuanPai = true;
Rule.BiYa = false;//不必压
}
if (gz[1] == '0')
{
Rule.ShouJu3 = true;
}
else if (gz[1] == '1')
{
Rule.MeiJu3 = true;
}
if (gz[2] == '0')
{
Rule.SiDai3 = true;
}
else if (gz[2] == '1')
{
Rule.SiDai2 = true;
}
if (gz[8] == '0')
{
GamePack.Info.PlayNum = 2;
}
else if (gz[8] == '1')
{
GamePack.Info.PlayNum = 3;
}
Rule.XianShenYuPai = gz[3] == '1';
Rule.HongTao10ZhaNiao = gz[4] == '1';
Rule.BaoZhuang = gz[5] == '1';
Rule.AAAIsZhaDan = gz[6] == '1';
Rule.XiaJiaBaoDan = gz[7] == '1';
Rule.ZhaDanDeFen = gz[9] == '1';
Rule.HeiTao3BiChu = gz[11] == '1';
switch (gz[10]) //设置托管
{
case '0':
Rule.TuoGuanNum = 0;
break;
case '1':
Rule.TuoGuanNum = 1;
break;
case '2':
Rule.TuoGuanNum = 3;
break;
case '3':
Rule.TuoGuanNum = 5;
break;
}
}
/// <summary>
/// 闹钟计时器
/// </summary>
public int TimeNum = 0;
/// <summary>
/// 包庄托管
/// </summary>
void BaoZhuangTuoGuan()
{
// var seat = GamePack.Info.WhoPlay - 1;
int count = 0;
for (int i = 0; i < GamePack.Info.PlayNum; i++)
{
var pl = this.DeskGameDo.desk[i];
if (pl != null && pl.isDePosit)
{
count++;
}
}
if (count == 0) return; //不需要托管
//GamePack.Info.PlayTuoGauan[seat] = 1;
for (byte i = 0; i < GamePack.Info.PlayNum; i++)
{
var pl = this.DeskGameDo.desk[i];
if (GamePack.Info.BaoZhuang[i] == 0 && pl != null && pl.isDePosit)
{
GamePack.Info.BaoZhuang[i] = 2;
}
}
Debug.Info("包庄托管!GameDo");
GameDo();
}
/// <summary>
/// 返回黑桃三的下标
/// </summary>
/// <param name="cards">可以出的牌组合</param>
/// <param name="index">返回黑桃三的下标</param>
/// <returns>false没有黑桃三 true有黑桃三</returns>
bool GetHei3Index(List<List<TCardInfoPdkF>> cards, out int index)
{
index = -1;
try
{
if (cards == null || cards.Count <= 0) return false;
bool isfirstChu = GamePack.Info.PlayNum == 2 ? GamePack.Info.ShenYuCard[0] == GamePack.Info.ShenYuCard[1]
: GamePack.Info.ShenYuCard[0] == GamePack.Info.ShenYuCard[1] && GamePack.Info.ShenYuCard[1] == GamePack.Info.ShenYuCard[2];
if (!isfirstChu) return false; //如果不是第一次出牌, 就不管
for (int i = 0; i < cards.Count; i++)
{
if (cards[i] == null || cards[i].Count <= 0) continue;
if (cards[i][0].Flower == 1 && cards[i][0].GameNum == 3)
{
index = i;
return true;
}
}
return false;
}
catch (Exception e)
{
Debug.Error($"返回黑桃三的下标 msg:{e.Message},code:{e.StackTrace}");
}
return false;
}
/// <summary>
/// 打牌托管
/// </summary>
void DaPaiTuoGuan()
{
var seat = GamePack.Info.WhoPlay - 1;
var pl = this.DeskGameDo.desk[seat];
if (pl == null) return; //不需要托管
if (Rule.BiYa)
{
if (pl.outline == 0)
{//玩家没有离线
if (!pl.isDePosit) return; //不需要托管
}
else
{//玩家离线
if (!pl.isDePosit && GamePack.Info.MaxPlayCard.GameNum <= 0) return;
}
}
else
{
if (!pl.isDePosit) return; //不需要托管
}
//GamePack.Info.PlayTuoGauan[seat] = 1; //加这个是为了兼容老客户端
if (GamePack.Info.MaxPlayCard.GameNum <= 0)
{ //托管先出
var tishi = PdkCardAlgorithm.GetTipCard(GamePack.Info.MaxPlayCard,
GamePack.CardPack.Cards[GamePack.Info.WhoPlay - 1].CardInfos.Where(x => x.GameState == 1).ToArray(),
GamePack.Info.MaxPlayCard.Pos == 0 ? null : GamePack.CardPack.Cards[GamePack.Info.MaxPlayCard.Pos - 1].CardInfos,
Rule.AAAIsZhaDan);
var idx = Rule.XiaJiaBaoDan && GamePack.Info.ShenYuCard[GetNextPos(GamePack.Info.WhoPlay) - 1] == 1 ? tishi.Count - 1 : 0;
if (Rule.HeiTao3BiChu && logicMemory.WarCount == 0)
{//如果首局黑桃三首次必出,第一次出牌就必出黑桃三
var h3 = GetHei3Index(tishi, out var idx3);
if (h3 && idx3 >= 0)
{
idx = idx3;
}
}
var payCard = new PlayOutCardPdkF();
payCard.Pos = (byte)GamePack.Info.WhoPlay;
payCard.Type = CardType1.DanZhang;
payCard.GameNum = tishi[idx][0].GameNum;
payCard.Ids = tishi[idx].Select(x => x.ID).ToArray();
Log($"who:{GamePack.Info.WhoPlay}先出 ,托管出的牌:{payCard}");
GamePack.Info.ActivePlayCard = payCard;
}
else
{
var shoupai = GamePack.CardPack.Cards[GamePack.Info.WhoPlay - 1].CardInfos.Where(x => x.GameState == 1).ToArray();
var tishi = PdkCardAlgorithm.GetTipCard(GamePack.Info.MaxPlayCard,
shoupai,
GamePack.Info.MaxPlayCard.Pos == 0 ? null : GamePack.CardPack.Cards[GamePack.Info.MaxPlayCard.Pos - 1].CardInfos,
Rule.AAAIsZhaDan, true);
var payCard = new PlayOutCardPdkF();
payCard.Pos = (byte)GamePack.Info.WhoPlay;
if (tishi == null || tishi.Count <= 0)
{
payCard.Type = CardType1.None;
}
else
{
if (pl.outline == 1 && !pl.isDePosit) return; //玩家离线并且没有到托管时间
payCard.Type = PdkCardAlgorithm.IsZhaDan(tishi[tishi.Count - 1].ToArray(), Rule.AAAIsZhaDan) ? CardType1.ZhaDan : GamePack.Info.MaxPlayCard.Type;
var idx = Rule.XiaJiaBaoDan && GamePack.Info.ShenYuCard[GetNextPos(GamePack.Info.WhoPlay) - 1] == 1 && payCard.Type == CardType1.DanZhang ? 0 : tishi.Count - 1;
payCard.GameNum = tishi[idx][0].GameNum;
payCard.Ids = tishi[idx].Select(x => x.ID).ToArray();
if (payCard.Type == CardType1.FeiJi || payCard.Type == CardType1.SanDai2)
{
int n = (payCard.Ids.Length / 3) * 2;
var chaCard = shoupai.Except(tishi[idx]);
List<TCardInfoPdkF> chupais = new List<TCardInfoPdkF>(16);
chupais.AddRange(tishi[idx]);
chupais.AddRange(chaCard.Reverse().Take(n));
payCard.Ids = chupais.Select(x => x.ID).ToArray();
}
}
Log($"who:{GamePack.Info.WhoPlay}跟牌 pai:{GamePack.Info.MaxPlayCard}托管出的牌:{payCard}");
GamePack.Info.ActivePlayCard = payCard;
}
Debug.Info("打牌托管GameDo!");
GameDo();
}
/// <summary>
/// 游戏临时加载的初始化
/// </summary>
public void LoadInit()
{
logicMemory.Init();
TimeNum = 0;
}
}
}

View File

@ -0,0 +1,108 @@
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net48</TargetFramework>
<UseWindowsForms>true</UseWindowsForms>
<RootNamespace>PdkFriendServer</RootNamespace>
<AssemblyName>PdkFriendServer</AssemblyName>
<Deterministic>true</Deterministic>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType>
<Platforms>AnyCPU</Platforms>
<Configurations>Debug;Release</Configurations>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|AnyCPU'">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>..\exe\PdkFriendServer\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|AnyCPU'">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>..\exe\PdkFriendServer_Re\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Costura.Fody" PrivateAssets="all" />
<PackageReference Include="Fody" PrivateAssets="all" />
<PackageReference Include="MessagePack.Annotations" />
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" />
<PackageReference Include="Microsoft.NET.StringTools" />
<PackageReference Include="System.Buffers" />
<PackageReference Include="System.Memory" />
<PackageReference Include="System.Numerics.Vectors" />
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" />
<PackageReference Include="System.Threading.Tasks.Extensions" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ServerCore\ServerCore.csproj" />
<ProjectReference Include="..\GameFix\GameFix.csproj" />
<ProjectReference Include="..\GameModule\GameModule.csproj" />
<ProjectReference Include="..\GlobalSever\GlobalSever.csproj" />
<ProjectReference Include="..\MrWu\MrWu.csproj" />
<ProjectReference Include="..\NetWorkMessage\NetWorkMessage.csproj" />
<ProjectReference Include="..\ObjectModel\ObjectModel.csproj" />
<ProjectReference Include="..\ServerData\ServerData.csproj" />
</ItemGroup>
<!-- <ItemGroup>-->
<!-- <Compile Include="..\..\hjha_Client\Assets\ScriptCode\UnityGame\GamePlay\Card\Common\PaoDeKuaiF\GameFix\**\*.cs">-->
<!-- <Link>GameFix\%(RecursiveDir)%(Filename)%(Extension)</Link>-->
<!-- </Compile>-->
<!-- </ItemGroup>-->
<ItemGroup>
<Compile Update="Form1.cs">
<SubType>Form</SubType>
</Compile>
<Compile Update="Form1.Designer.cs">
<DependentUpon>Form1.cs</DependentUpon>
</Compile>
<EmbeddedResource Update="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
<SubType>Designer</SubType>
</EmbeddedResource>
<Compile Update="Properties\Resources.Designer.cs">
<AutoGen>true</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
<DesignTime>true</DesignTime>
</Compile>
<None Update="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
<Compile Update="Properties\Settings.Designer.cs">
<AutoGen>true</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>true</DesignTimeSharedInput>
</Compile>
<None Update="App.config">
<SubType>Designer</SubType>
</None>
</ItemGroup>
</Project>

View File

@ -0,0 +1,30 @@
using GlobalSever.Form;
using PdkFriendServer.GlobalManager;
using PdkFriendServer.Logic;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace PdkFriendServer
{
internal static class Program
{
/// <summary>
/// 应用程序的主入口点。
/// </summary>
[STAThread]
static void Main(string[] args)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new ServerForm(new GameServerProxy(), args));
//PdkGameMain main = new PdkGameMain(null);
//main.Test();
//Console.ReadLine();
}
}
}

View File

@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// 有关程序集的一般信息由以下
// 控制。更改这些特性值可修改
// 与程序集关联的信息。
[assembly: AssemblyTitle("PdkFriendServer")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("PdkFriendServer")]
[assembly: AssemblyCopyright("Copyright © 2024")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// 将 ComVisible 设置为 false 会使此程序集中的类型
//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型
//请将此类型的 ComVisible 特性设置为 true。
[assembly: ComVisible(false)]
// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
[assembly: Guid("51c87339-4bbc-425a-b2d1-4488d0841b42")]
// 程序集的版本信息由下列四个值组成:
//
// 主版本
// 次版本
// 生成号
// 修订号
//
//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值
//通过使用 "*",如下所示:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@ -0,0 +1,71 @@
//------------------------------------------------------------------------------
// <auto-generated>
// 此代码由工具生成。
// 运行时版本: 4.0.30319.42000
//
// 对此文件的更改可能导致不正确的行为,如果
// 重新生成代码,则所做更改将丢失。
// </auto-generated>
//------------------------------------------------------------------------------
namespace PdkFriendServer.Properties
{
/// <summary>
/// 强类型资源类,用于查找本地化字符串等。
/// </summary>
// 此类是由 StronglyTypedResourceBuilder
// 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。
// 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen
// (以 /str 作为命令选项),或重新生成 VS 项目。
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources
{
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources()
{
}
/// <summary>
/// 返回此类使用的缓存 ResourceManager 实例。
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager
{
get
{
if ((resourceMan == null))
{
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("PdkFriendServer.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// 重写当前线程的 CurrentUICulture 属性,对
/// 使用此强类型资源类的所有资源查找执行重写。
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture
{
get
{
return resourceCulture;
}
set
{
resourceCulture = value;
}
}
}
}

View File

@ -0,0 +1,117 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@ -0,0 +1,30 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace PdkFriendServer.Properties
{
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
{
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default
{
get
{
return defaultInstance;
}
}
}
}

View File

@ -0,0 +1,7 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)">
<Profiles>
<Profile Name="(Default)" />
</Profiles>
<Settings />
</SettingsFile>