commit 889e9f7c6c89776bfb6e61622f7578f7b97d409e Author: fma06 <3122929427@qq.com> Date: Fri Sep 1 10:51:28 2023 +0800 初始化 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ac17331 --- /dev/null +++ b/.gitignore @@ -0,0 +1,50 @@ +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* + +target +.project +.DS_Store +.classpath +.settings +*.log +*.log.* + +.idea +.gradle +build +bin +out +*.iml + + +target +.project +.DS_Store +.classpath +.settings +/.classpath +/target +/.settings +/.project +/ratel-landlords/.project +.vscode \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/PROTOCO_CN.md b/PROTOCO_CN.md new file mode 100644 index 0000000..19aa894 --- /dev/null +++ b/PROTOCO_CN.md @@ -0,0 +1,176 @@ +[toc] +# Ratel-Client开发文档 +## 介绍 +### 什么是Ratel +[Ratel](https://github.com/ainilili/ratel) 是一个可以在命令行中玩斗地主的项目,可以使用小巧的jar包在拥有JVM环境的终端中进行游戏,同时支持人人对战和人机对战两种模式,丰富你的空闲时间! + +Ratel使用Java语言开发,[Netty 4.x](https://github.com/netty/netty)网络框架搭配[protobuf](https://github.com/protocolbuffers/protobuf)数据协议,可以支持多客户端同时游戏。 + +### Ratel-Client扩展 +Ratel面向响应式架构,通过事件码进行通讯,对于Ratel-Client,支持跨平台扩展,换一种说法,任何后端语言都可以开发Ratel-Client! + +在开发Ratel-Client前应该知道: +- Ratel Server-Client交互网络协议为``TCP/IP``。 +- Ratel Server-Client交互数据协议为[protobuf](https://github.com/protocolbuffers/protobuf)。 +- Ratel以事件为驱动,在Client将各个环节串联起来。 +- Ratel所有的文案都由Client显示。 + +## 对接 +### 架构你的客户端 +我们可以使用任何后端语言就重写Ratel客户端,Ratel默认的客户端的由Java语言编写,如果你想使用其他语言重写,以下是我们推荐的一种架构: +![](https://user-gold-cdn.xitu.io/2018/11/17/16720fa649dfaea0?w=898&h=500&f=png&s=33655) + +这种架构对于事件的处理非常友好,你可以设计一个抽象的``Event-Listener``接口,然后开发不同的实现去处理不同``CODE``对应的响应数据,例如一个而简单的例子——Poker的显示,以下是我们的处理流程的伪代码: +``` +1、对服务端响应数据解码 -> + +decode(msg) + +2、解码后的数据 -> + +ClientData{ + String code; + String data; +} + +3、通过code寻找对应的EventListener -> + +showPokersEventListener = Map.get(code) + +4、处理响应数据 -> + +showPokersEventListener.call(server, data){ + show(data); + server.write(msg); +} +``` +以上只是简单的``Server-Client``的交互流程,有时候可能会出现``Client-Client``的场景,例如客户端的选项面板的显示,在我们从A层切换到B层,再从B层返回到A层,这时就需要做``Client-Client``的交互。 + +当然,大多数的交互重点集中在``Server-Client``,而另一方面,客户端大多都是在处理并显示服务端响应的数据,对于真正的业务交互很少,这对于客户端来说,只要将事件绝对的丰富,那么客户端的流程就会绝对的灵活。因此,Ratel的客户端响应事件相比于服务端的响应事件数量多了几倍有余,所以这对于客户端的架构要求就是要有足够的灵活性,能够支持以下两个业务流: +- Server-Client-Server +- Server-Client-Client-Server + +之后,我们进入下一步! +### 定义数据实体 +对于客户端和服务端交互的数据,为了承载,我们需要设计两个类去存放编解码后的数据,值得一提的是,客户端和服务端的数据结构一样,都由``CODE``、``DATA``和``INFO``三个字段组成: +- CODE - 对应的事件 +- DATA - 传递的数据 +- INFO - 信息(暂时用不到) + +我们的编解码方式为``Protobuf``序列化,参考文件请看[这里](https://github.com/ainilili/ratel/tree/master/protoc-resource)。 + +### 对接协议 +在我们做好对接的准备工作之后,可以通过以下协议文档开始实现客户端的业务! + +#### 客户端事件 +##### 连接成功事件 + - ``CODE`` - CODE_CLIENT_CONNECT + - ``TYPE`` - TEXT + - ``DATA`` - 客户端被分配的ID + +##### 退出房间事件 + - ``CODE`` - CODE_CLIENT_EXIT + - ``TYPE`` - JSON + - ``DATA`` - 如下 + +字段名 | 含义 +---|--- +roomId | 房间ID +exitClientId | 退出者ID +exitClientNickname | 退出者昵称 + +参考数据 +``` +{"roomId":14,"exitClientId":64330,"exitClientNickname":"nico"} +``` + +##### 客户端踢出事件 + - ``CODE`` - CODE_CLIENT_KICK + - ``TYPE`` - Text + - ``DATA`` - NULL + +##### 设置昵称事件 + - ``CODE`` - CODE_CLIENT_NICKNAME_SET + - ``TYPE`` - JSON + - ``DATA`` - 如下 + +字段名 | 含义 +---|--- +invalidLength | 有效长度,当设置昵称超过10个字节会返回此字段 + +参考数据: +``` +{"invalidLength":10} +``` + +##### 抢地主-地主诞生事件 + - ``CODE`` - CODE_GAME_LANDLORD_CONFIRM + - ``TYPE`` - JSON + - ``DATA`` - 如下 + +字段名 | 含义 +---|--- +roomId | 房间ID +roomOwner | 房间所有者昵称 +roomClientCount | 房间人数 +landlordNickname | 地主昵称 +landlordId | 地主ID +additionalPokers | 额外的三张牌 + +参考数据: +``` +{"roomId":14,"roomOwner":"nico","roomClientCount":3,"landlordNickname":"robot_2","landlordId":-8,"additionalPokers":[{"level":"LEVEL_5","type":"DIAMOND"},{"level":"LEVEL_6","type":"CLUB"},{"level":"LEVEL_A","type":"DIAMOND"}]} +``` + +##### 抢地主-大家都没抢事件 + - ``CODE`` - CODE_GAME_LANDLORD_CYCLE + - ``TYPE`` - TEXT + - ``DATA`` - NULL + +TIP:该事件触发后会连续触发重新游戏事件 + +##### 抢地主-抢地主决策事件 + - ``CODE`` - CODE_GAME_LANDLORD_ELECT + - ``TYPE`` - JSON + - ``DATA`` - 如下 + +字段名 | 含义 +---|--- +roomId | 房间ID +roomOwner | 房间所有者昵称 +roomClientCount | 房间人数 +preClientNickname | 上一个客户端的昵称 +nextClientNickname | 下一个客户端的昵称 +nextClientId | 下一个客户端的ID + +参考数据: +``` +{"roomId":14,"roomOwner":"nico","roomClientCount":3,"preClientNickname":"nico1","nextClientNickname":"nico2","nextClientId":2} +``` + +##### 游戏结束事件 + - ``CODE`` - CODE_GAME_OVER + - ``TYPE`` - JSON + - ``DATA`` - 如下 + +字段名 | 含义 +---|--- +winnerNickname | 获胜者昵称 +winnerType | 获胜者类型(地主?农民) + +参考数据: +``` +{"winnerNickname":"nico","winnerType":"LANDLORD?PEASANT"} +``` + + + + + + + + + + + + diff --git a/README.md b/README.md new file mode 100644 index 0000000..ca528ba --- /dev/null +++ b/README.md @@ -0,0 +1,86 @@ +# Ratel + +[![GitHub forks](https://img.shields.io/github/forks/ainilili/ratel?style=flat-square)](https://github.com/ainilili/ratel/network) +![GitHub release (latest by date)](https://img.shields.io/github/v/release/ainilili/ratel?style=flat-square) +![GitHub all releases](https://img.shields.io/github/downloads/ainilili/ratel/total?logo=spring&style=flat-square) +[![GitHub stars](https://img.shields.io/github/stars/ainilili/ratel?logo=java&style=flat-square)](https://github.com/ainilili/ratel/stargazers) +[![GitHub license](https://img.shields.io/github/license/ainilili/ratel?logo=apache&style=flat-square)](https://github.com/ainilili/ratel/blob/master/LICENSE) +![Build ratel(Java with Maven)](https://github.com/ainilili/ratel/workflows/Build%20ratel(Java%20with%20Maven)/badge.svg?branch=master) +![Docker Image Version (latest by date)](https://img.shields.io/docker/v/kebyn/ratel?label=Docker&logo=docker&style=flat-square) + +## 介绍 +基于Netty实现的命令行斗地主游戏,为划水摸鱼而生~ + +> 新版开发中:[直通车](https://github.com/ratel-online),新增癞子模式,增加超时机制,完美复现欢乐斗地主,欢迎体验在线版 [http://rtol.isnico.com/](http://rtol.isnico.com/) + +## 安装 +首先下载打包,确保本地安装有maven及JRE环境: +```powershell +git clone https://github.com/ainilili/ratel.git +cd ratel +mvn install package +``` +接下来分别运行 ``landlords-client`` 和 ``landlords-server`` 的 ``target`` 文件夹下的Jar包: +```powershell +java -jar landlords-server/target/landlords-server-#{version}.jar -p 1024 +java -jar landlords-client/target/landlords-client-#{version}.jar -p 1024 -h 127.0.0.1 +``` +客户端亦可直接运行,程序会自动拉取[Serverlist](https://github.com/ainilili/ratel/blob/master/serverlist.json)中的公网服务器: +```powershell +java -jar landlords-client/target/landlords-client-#{version}.jar +``` +**注意**,实际运行中请将``#{version}``改为当前运行版本! +## 玩法介绍 +在线试玩:[传送门](http://ratel.isnico.com) + +![demo](demo.gif) + +### 出牌规则 +所有牌型: +``` +┌──┐──┐──┐──┐──┐──┐──┐──┐──┐──┐──┐──┐──┐──┐──┐ +│3 |4 |5 |6 |7 |8 |9 |10|J |Q |K |A |2 |S |X | +│♦ |♦ |♦ |♦ |♦ |♦ |♦ |♦ |♦ |♦ |♦ |♦ |♦ | | | +└──┘──┘──┘──┘──┘──┘──┘──┘──┘──┘──┘──┘──┘──┘──┘ +``` +示例: + - 王炸:``sx`` + - 顺子:``34567`` + - 三带一:``3334`` + - 飞机:``333444a2`` + - 单张10:``0``或者``t`` + - 单张A:``a``或者``1`` + - 封顶顺子:``34567890jqka`` + - 不想出牌: ``pass``或``p`` + - 退出: ``exit``或者``e`` + - [更多](https://zh.wikipedia.org/zh-sg/%E9%AC%A5%E5%9C%B0%E4%B8%BB) + +#### 协议支持 + - TCP + - Websocket + +Websocket协议的地址为 ``ws://host:port/ratel``,Websocket的端口需要在原端口基础上加1 (如果tcp端口为1024,则ws端口需要为1025) +## 划水俱乐部 +QQ群 ``948365095``,划水一时爽,一直划水一直爽! + +## 生态 + - [go-ratel-client](https://github.com/ZuoFuhong/go-ratel) + - [javafx-ratel-client](https://github.com/marmot-z/javafx-ratel-client) + - [javascript-ratel-client](https://github.com/marmot-z/js-ratel-client) + +## 教学 + - [Ratel浅析] (https://github.com/HelloGitHub-Team/Article/blob/master/contents/Java/landlords/content.md) + - [Ratel玩法视频教学] (https://www.bilibili.com/video/av97603585) + +## 更新日志 + - [更新日志](https://github.com/ainilili/ratel/blob/master/UPDATE.md) + +## 计划 + - 支持高级难度机器人 + +## More + - [Serverlist.json](https://github.com/ainilili/ratel/blob/master/serverlist.json) 是当前的服务器列表, 如果你的服务器部署着当前最新版本的服务端并且分享给大家,可以通过PR提交给我们! + - 如果您想贡献代码,非常欢迎提``PR``,我们将会合并优秀的代码. + - 如果您发现了``Bug``,非常欢迎提``Issue``给我们. + - 欢迎扩展其他语言的客户端. + - 联系我们请发邮件到 ``ainililia@163.com``. diff --git a/UPDATE.md b/UPDATE.md new file mode 100644 index 0000000..be7da85 --- /dev/null +++ b/UPDATE.md @@ -0,0 +1,13 @@ +> Version 1.0.0 Updated + +- Create room +- Join room +- Play game + +> Version 1.1.0 Updated + +- Service list selection +- The Robot model +- Nickname length verify +- Room timeout detection +- Let's replace the room timeout with Robot \ No newline at end of file diff --git a/demo.gif b/demo.gif new file mode 100644 index 0000000..36e3c2d Binary files /dev/null and b/demo.gif differ diff --git a/docker/README.md b/docker/README.md new file mode 100644 index 0000000..f92b340 --- /dev/null +++ b/docker/README.md @@ -0,0 +1,60 @@ +1. [安装`docker`](https://docs.docker.com/install/linux/docker-ce/ubuntu/#install-using-the-convenience-script) + ``` + curl -fsSL https://get.docker.com -o get-docker.sh + sudo sh get-docker.sh + ``` +2. 客户端 + + 直接使用已经编译好的客户端 + - `docker` 运行客户端,默认加入公网服务器 `39.105.65.8` + ``` + docker run --rm -it kebyn/ratel:client + ``` + 等同于 + ``` + docker run --rm -it kebyn/ratel:client -- 'java -jar *.jar -h 39.105.65.8' + ``` + - `docker` 运行客户端,加入公网服务器 `x.x.x.x` + ``` + docker run --rm -it kebyn/ratel:client -- 'java -jar *.jar -h x.x.x.x' + ``` + + 自行编译 `docker` 客户端 + - 下载并编译 + ``` + git clone https://github.com/ainilili/ratel.git + cd ratel/docker/client + docker build -f Dockerfile -t ratel:client . + ``` + - 使用 `docker` 运行客户端,默认加入公网服务器 `39.105.65.8` + ``` + docker run --rm -it ratel:client + ``` + 等同于 + ``` + docker run --rm -it ratel:client -- 'java -jar *.jar -h 39.105.65.8' + ``` + - `docker` 运行客户端,加入公网服务器 `x.x.x.x` + ``` + docker run --rm -it kebyn/ratel:client -- 'java -jar *.jar -h x.x.x.x' + ``` +3. 服务端 + + 直接使用已经编译好的服务端 + - `docker` 运行客户端,并指定使用`1024`端口 + ``` + docker run --rm -d -p 1024:1024 kebyn/ratel:server + ``` + + 自行编译 `docker` 客户端 + - 下载并编译 + ``` + git clone https://github.com/ainilili/ratel.git + cd ratel/docker/server + docker build -f Dockerfile -t ratel:server . + ``` + - 使用 `docker` 运行客户端 + ``` + docker run --rm -d -p 1024:1024 ratel:server + ``` + 等同于 + ``` + docker run --rm -d -p 1024:1024 ratel:server -- 'java -jar *.jar -p 1024' + ``` + > 确保服务器防火墙允许`1024`端口访问,并且没有其它应用占用`1024`端口 diff --git a/docker/client/Dockerfile b/docker/client/Dockerfile new file mode 100644 index 0000000..a325c5f --- /dev/null +++ b/docker/client/Dockerfile @@ -0,0 +1,10 @@ +FROM maven:3-jdk-8 +RUN git clone https://github.com/ainilili/ratel.git +WORKDIR /ratel +RUN mvn install package + +FROM openjdk:8-slim +COPY --from=0 /ratel/landlords-client/target/*.jar /opt +WORKDIR /opt +ENTRYPOINT ["bash", "-c"] +CMD ["java -jar *.jar -h 39.105.65.8"] diff --git a/docker/server/Dockerfile b/docker/server/Dockerfile new file mode 100644 index 0000000..c55d199 --- /dev/null +++ b/docker/server/Dockerfile @@ -0,0 +1,10 @@ +FROM maven:3-jdk-8 +RUN git clone https://github.com/ainilili/ratel.git +WORKDIR /ratel +RUN mvn install package + +FROM openjdk:8-slim +COPY --from=0 /ratel/landlords-server/target/*.jar /opt +WORKDIR /opt +ENTRYPOINT ["bash", "-c"] +CMD ["java -jar *.jar -p 1024"] diff --git a/landlords-client/pom.xml b/landlords-client/pom.xml new file mode 100644 index 0000000..0b1f022 --- /dev/null +++ b/landlords-client/pom.xml @@ -0,0 +1,59 @@ + + 4.0.0 + landlords-client + landlords-client + This is a console version of the fight landlord game + + + org.nico.ratel.landlords.client.SimpleClient + + + + com.smallnico.ratel + landlords + 1.4.0 + + + + + com.smallnico.ratel + landlords-common + 1.4.0 + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + ${start-class} + + + + + repackage + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 1.8 + 1.8 + + -parameters + + true + + + + + + \ No newline at end of file diff --git a/landlords-client/src/main/java/org/nico/ratel/landlords/client/SimpleClient.java b/landlords-client/src/main/java/org/nico/ratel/landlords/client/SimpleClient.java new file mode 100644 index 0000000..160db57 --- /dev/null +++ b/landlords-client/src/main/java/org/nico/ratel/landlords/client/SimpleClient.java @@ -0,0 +1,100 @@ +package org.nico.ratel.landlords.client; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.net.URL; +import java.util.List; +import java.util.Objects; + +import org.nico.noson.Noson; +import org.nico.noson.entity.NoType; +import org.nico.ratel.landlords.client.entity.User; +import org.nico.ratel.landlords.client.proxy.ProtobufProxy; +import org.nico.ratel.landlords.client.proxy.WebsocketProxy; +import org.nico.ratel.landlords.features.Features; +import org.nico.ratel.landlords.print.SimplePrinter; +import org.nico.ratel.landlords.print.SimpleWriter; +import org.nico.ratel.landlords.utils.StreamUtils; + +public class SimpleClient { + + public static int id = -1; + + public final static String VERSION = Features.VERSION_1_3_0; + + public static String serverAddress; + + public static int port = 1024; + + public static String protocol = "pb"; + + private final static String[] serverAddressSource = new String[]{ + "https://raw.githubusercontent.com/ainilili/ratel/master/serverlist.json", //Source + "https://cdn.jsdelivr.net/gh/ainilili/ratel@master/serverlist.json", //CN CDN + "https://raw.fastgit.org/ainilili/ratel/master/serverlist.json", //HongKong CDN + "https://cdn.staticaly.com/gh/ainilili/ratel/master/serverlist.json", //Japanese CDN + "https://ghproxy.com/https://raw.githubusercontent.com/ainilili/ratel/master/serverlist.json", //Korea CDN + "https://gitee.com/ainilili/ratel/raw/master/serverlist.json" //CN Gitee + }; + + public static void main(String[] args) throws InterruptedException, IOException, URISyntaxException { + if (args != null && args.length > 0) { + for (int index = 0; index < args.length; index = index + 2) { + if (index + 1 < args.length) { + if (args[index].equalsIgnoreCase("-p") || args[index].equalsIgnoreCase("-port")) { + port = Integer.parseInt(args[index + 1]); + } + if (args[index].equalsIgnoreCase("-h") || args[index].equalsIgnoreCase("-host")) { + serverAddress = args[index + 1]; + } + if (args[index].equalsIgnoreCase("-ptl") || args[index].equalsIgnoreCase("-protocol")) { + protocol = args[index + 1]; + } + } + } + } + if (serverAddress == null) { + List serverAddressList = getServerAddressList(); + if (serverAddressList == null || serverAddressList.size() == 0) { + throw new RuntimeException("Please use '-host' to setting server address."); + } + + SimplePrinter.printNotice("Please select a server:"); + for (int i = 0; i < serverAddressList.size(); i++) { + SimplePrinter.printNotice((i + 1) + ". " + serverAddressList.get(i)); + } + int serverPick = Integer.parseInt(SimpleWriter.write(User.INSTANCE.getNickname(), "option")); + while (serverPick < 1 || serverPick > serverAddressList.size()) { + try { + SimplePrinter.printNotice("The server address does not exist!"); + serverPick = Integer.parseInt(SimpleWriter.write(User.INSTANCE.getNickname(), "option")); + } catch (NumberFormatException ignore) {} + } + serverAddress = serverAddressList.get(serverPick - 1); + String[] elements = serverAddress.split(":"); + serverAddress = elements[0]; + port = Integer.parseInt(elements[1]); + } + + if (Objects.equals(protocol, "pb")) { + new ProtobufProxy().connect(serverAddress, port); + } else if (Objects.equals(protocol, "ws")) { + new WebsocketProxy().connect(serverAddress, port + 1); + } else { + throw new UnsupportedOperationException("Unsupported protocol " + protocol); + } + } + + private static List getServerAddressList() { + for (String serverAddressSource : serverAddressSource) { + try { + String serverInfo = StreamUtils.convertToString(new URL(serverAddressSource)); + return Noson.convert(serverInfo, new NoType>() {}); + } catch (IOException e) { + SimplePrinter.printNotice("Try connected " + serverAddressSource + " failed: " + e.getMessage()); + } + } + return null; + } + +} diff --git a/landlords-client/src/main/java/org/nico/ratel/landlords/client/entity/User.java b/landlords-client/src/main/java/org/nico/ratel/landlords/client/entity/User.java new file mode 100644 index 0000000..fc4b610 --- /dev/null +++ b/landlords-client/src/main/java/org/nico/ratel/landlords/client/entity/User.java @@ -0,0 +1,39 @@ +package org.nico.ratel.landlords.client.entity; + +public class User { + public static final User INSTANCE = new User(); + + /** 是否游戏中 */ + private volatile boolean isPlaying = false; + + /** 是否观战中 */ + private volatile boolean isWatching = false; + + private String nickname = "player"; + + private User() {} + + public boolean isPlaying() { + return isPlaying; + } + + public void setPlaying(boolean playing) { + isPlaying = playing; + } + + public boolean isWatching() { + return isWatching; + } + + public void setWatching(boolean watching) { + isWatching = watching; + } + + public String getNickname() { + return nickname; + } + + public void setNickname(String nickname) { + this.nickname = nickname; + } +} diff --git a/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener.java b/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener.java new file mode 100644 index 0000000..f823525 --- /dev/null +++ b/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener.java @@ -0,0 +1,60 @@ +package org.nico.ratel.landlords.client.event; + +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; + +import org.nico.ratel.landlords.channel.ChannelUtils; +import org.nico.ratel.landlords.entity.Poker; +import org.nico.ratel.landlords.enums.ClientEventCode; +import org.nico.ratel.landlords.enums.ServerEventCode; + +import io.netty.channel.Channel; +import io.netty.channel.ChannelFuture; + +public abstract class ClientEventListener { + + public abstract void call(Channel channel, String data); + + public final static Map LISTENER_MAP = new HashMap<>(); + + private final static String LISTENER_PREFIX = "org.nico.ratel.landlords.client.event.ClientEventListener_"; + + protected static List lastPokers = null; + protected static String lastSellClientNickname = null; + protected static String lastSellClientType = null; + + protected static void initLastSellInfo() { + lastPokers = null; + lastSellClientNickname = null; + lastSellClientType = null; + } + + @SuppressWarnings("unchecked") + public static ClientEventListener get(ClientEventCode code) { + ClientEventListener listener; + try { + if (ClientEventListener.LISTENER_MAP.containsKey(code)) { + listener = ClientEventListener.LISTENER_MAP.get(code); + } else { + String eventListener = LISTENER_PREFIX + code.name().toUpperCase(Locale.ROOT); + Class listenerClass = (Class) Class.forName(eventListener); + listener = listenerClass.newInstance(); + ClientEventListener.LISTENER_MAP.put(code, listener); + } + return listener; + } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) { + e.printStackTrace(); + } + return null; + } + + protected ChannelFuture pushToServer(Channel channel, ServerEventCode code, String datas) { + return ChannelUtils.pushToServer(channel, code, datas); + } + + protected ChannelFuture pushToServer(Channel channel, ServerEventCode code) { + return pushToServer(channel, code, null); + } +} diff --git a/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_CLIENT_CONNECT.java b/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_CLIENT_CONNECT.java new file mode 100644 index 0000000..8d630da --- /dev/null +++ b/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_CLIENT_CONNECT.java @@ -0,0 +1,28 @@ +package org.nico.ratel.landlords.client.event; + +import org.nico.noson.Noson; +import org.nico.ratel.landlords.client.SimpleClient; +import org.nico.ratel.landlords.enums.ServerEventCode; +import org.nico.ratel.landlords.features.Features; +import org.nico.ratel.landlords.helper.MapHelper; +import org.nico.ratel.landlords.print.SimplePrinter; + +import io.netty.channel.Channel; +import org.nico.ratel.landlords.utils.JsonUtils; + +import java.util.HashMap; +import java.util.Map; + +public class ClientEventListener_CODE_CLIENT_CONNECT extends ClientEventListener { + + @Override + public void call(Channel channel, String data) { + SimplePrinter.printNotice("Connected to server. Welcome to ratel!"); + SimpleClient.id = Integer.parseInt(data); + + Map infos = new HashMap<>(); + infos.put("version", SimpleClient.VERSION); + pushToServer(channel, ServerEventCode.CODE_CLIENT_INFO_SET, Noson.reversal(infos)); + } + +} diff --git a/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_CLIENT_EXIT.java b/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_CLIENT_EXIT.java new file mode 100644 index 0000000..5f2f241 --- /dev/null +++ b/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_CLIENT_EXIT.java @@ -0,0 +1,30 @@ +package org.nico.ratel.landlords.client.event; + +import java.util.Map; + +import org.nico.ratel.landlords.client.SimpleClient; +import org.nico.ratel.landlords.enums.ClientEventCode; +import org.nico.ratel.landlords.helper.MapHelper; +import org.nico.ratel.landlords.print.SimplePrinter; + +import io.netty.channel.Channel; + +public class ClientEventListener_CODE_CLIENT_EXIT extends ClientEventListener { + + @Override + public void call(Channel channel, String data) { + Map map = MapHelper.parser(data); + + Integer exitClientId = (Integer) map.get("exitClientId"); + + String role; + if (exitClientId == SimpleClient.id) { + role = "You"; + } else { + role = String.valueOf(map.get("exitClientNickname")); + } + SimplePrinter.printNotice(role + " left the room. Room disbanded!\n"); + + get(ClientEventCode.CODE_SHOW_OPTIONS).call(channel, data); + } +} diff --git a/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_CLIENT_KICK.java b/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_CLIENT_KICK.java new file mode 100644 index 0000000..c72f768 --- /dev/null +++ b/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_CLIENT_KICK.java @@ -0,0 +1,18 @@ +package org.nico.ratel.landlords.client.event; + +import org.nico.ratel.landlords.enums.ClientEventCode; +import org.nico.ratel.landlords.print.SimplePrinter; + +import io.netty.channel.Channel; + +public class ClientEventListener_CODE_CLIENT_KICK extends ClientEventListener { + + @Override + public void call(Channel channel, String data) { + + SimplePrinter.printNotice("You have been kicked from the room for being idle.\n"); + + get(ClientEventCode.CODE_SHOW_OPTIONS).call(channel, data); + } + +} diff --git a/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_CLIENT_NICKNAME_SET.java b/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_CLIENT_NICKNAME_SET.java new file mode 100644 index 0000000..63b6b89 --- /dev/null +++ b/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_CLIENT_NICKNAME_SET.java @@ -0,0 +1,44 @@ +package org.nico.ratel.landlords.client.event; + +import java.util.Map; + +import org.nico.noson.util.string.StringUtils; +import org.nico.ratel.landlords.client.entity.User; +import org.nico.ratel.landlords.enums.ClientEventCode; +import org.nico.ratel.landlords.enums.ServerEventCode; +import org.nico.ratel.landlords.helper.MapHelper; +import org.nico.ratel.landlords.print.SimplePrinter; +import org.nico.ratel.landlords.print.SimpleWriter; + +import io.netty.channel.Channel; + +public class ClientEventListener_CODE_CLIENT_NICKNAME_SET extends ClientEventListener { + + public static final int NICKNAME_MAX_LENGTH = 10; + + @Override + public void call(Channel channel, String data) { + + // If it is not the first time that the user is prompted to enter nickname + // If first time, data = null or "" otherwise not empty + if (StringUtils.isNotBlank(data)) { + Map dataMap = MapHelper.parser(data); + if (dataMap.containsKey("invalidLength")) { + SimplePrinter.printNotice("Your nickname has invalid length: " + dataMap.get("invalidLength")); + } + } + SimplePrinter.printNotice("Please set your nickname (upto " + NICKNAME_MAX_LENGTH + " characters)"); + String nickname = SimpleWriter.write(User.INSTANCE.getNickname(), "nickname"); + + // If the length of nickname is more that NICKNAME_MAX_LENGTH + if (nickname.trim().length() > NICKNAME_MAX_LENGTH) { + String result = MapHelper.newInstance().put("invalidLength", nickname.trim().length()).json(); + get(ClientEventCode.CODE_CLIENT_NICKNAME_SET).call(channel, result); + } else { + pushToServer(channel, ServerEventCode.CODE_CLIENT_NICKNAME_SET, nickname); + User.INSTANCE.setNickname(nickname); + } + } + + +} diff --git a/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_GAME_LANDLORD_CONFIRM.java b/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_GAME_LANDLORD_CONFIRM.java new file mode 100644 index 0000000..c6098be --- /dev/null +++ b/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_GAME_LANDLORD_CONFIRM.java @@ -0,0 +1,31 @@ +package org.nico.ratel.landlords.client.event; + +import java.util.List; +import java.util.Map; + +import org.nico.noson.Noson; +import org.nico.noson.entity.NoType; +import org.nico.ratel.landlords.entity.Poker; +import org.nico.ratel.landlords.enums.ServerEventCode; +import org.nico.ratel.landlords.helper.MapHelper; +import org.nico.ratel.landlords.print.SimplePrinter; + +import io.netty.channel.Channel; + +public class ClientEventListener_CODE_GAME_LANDLORD_CONFIRM extends ClientEventListener { + + @Override + public void call(Channel channel, String data) { + Map map = MapHelper.parser(data); + + String landlordNickname = String.valueOf(map.get("landlordNickname")); + + SimplePrinter.printNotice(landlordNickname + " has become the landlord and gotten three extra cards"); + + List additionalPokers = Noson.convert(map.get("additionalPokers"), new NoType>() {}); + SimplePrinter.printPokers(additionalPokers); + + pushToServer(channel, ServerEventCode.CODE_GAME_POKER_PLAY_REDIRECT); + } + +} diff --git a/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_GAME_LANDLORD_CYCLE.java b/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_GAME_LANDLORD_CYCLE.java new file mode 100644 index 0000000..e34e21d --- /dev/null +++ b/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_GAME_LANDLORD_CYCLE.java @@ -0,0 +1,15 @@ +package org.nico.ratel.landlords.client.event; + +import org.nico.ratel.landlords.print.SimplePrinter; + +import io.netty.channel.Channel; + +public class ClientEventListener_CODE_GAME_LANDLORD_CYCLE extends ClientEventListener { + + @Override + public void call(Channel channel, String data) { + SimplePrinter.printNotice("No player takes the landlord, so redealing cards."); + + } + +} diff --git a/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_GAME_LANDLORD_ELECT.java b/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_GAME_LANDLORD_ELECT.java new file mode 100644 index 0000000..20654fb --- /dev/null +++ b/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_GAME_LANDLORD_ELECT.java @@ -0,0 +1,44 @@ +package org.nico.ratel.landlords.client.event; + +import java.util.Map; + +import org.nico.ratel.landlords.client.SimpleClient; +import org.nico.ratel.landlords.client.entity.User; +import org.nico.ratel.landlords.enums.ServerEventCode; +import org.nico.ratel.landlords.helper.MapHelper; +import org.nico.ratel.landlords.print.SimplePrinter; +import org.nico.ratel.landlords.print.SimpleWriter; + +import io.netty.channel.Channel; + +public class ClientEventListener_CODE_GAME_LANDLORD_ELECT extends ClientEventListener { + + @Override + public void call(Channel channel, String data) { + Map map = MapHelper.parser(data); + int turnClientId = (int) map.get("nextClientId"); + + if (map.containsKey("preClientNickname")) { + SimplePrinter.printNotice(map.get("preClientNickname") + " don't rob the landlord!"); + } + + if(turnClientId == SimpleClient.id) { + SimplePrinter.printNotice("It's your turn. Do you want to rob the landlord? [Y/N] (enter [exit|e] to exit current room)"); + String line = SimpleWriter.write(User.INSTANCE.getNickname(), "Y/N"); + if (line.equalsIgnoreCase("exit") || line.equalsIgnoreCase("e")) { + pushToServer(channel, ServerEventCode.CODE_CLIENT_EXIT); + } else if (line.equalsIgnoreCase("Y")) { + pushToServer(channel, ServerEventCode.CODE_GAME_LANDLORD_ELECT, "TRUE"); + } else if (line.equalsIgnoreCase("N")) { + pushToServer(channel, ServerEventCode.CODE_GAME_LANDLORD_ELECT, "FALSE"); + } else { + SimplePrinter.printNotice("Invalid options"); + call(channel, data); + } + } else { + SimplePrinter.printNotice("It's " + map.get("nextClientNickname") + "'s turn. Please wait patiently for his/her confirmation !"); + } + + } + +} diff --git a/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_GAME_OVER.java b/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_GAME_OVER.java new file mode 100644 index 0000000..b267655 --- /dev/null +++ b/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_GAME_OVER.java @@ -0,0 +1,45 @@ +package org.nico.ratel.landlords.client.event; + +import java.util.List; +import java.util.Map; +import java.util.Objects; + +import org.nico.noson.Noson; +import org.nico.noson.entity.NoType; +import org.nico.ratel.landlords.client.SimpleClient; +import org.nico.ratel.landlords.entity.Poker; +import org.nico.ratel.landlords.helper.MapHelper; +import org.nico.ratel.landlords.print.SimplePrinter; + +import io.netty.channel.Channel; + +public class ClientEventListener_CODE_GAME_OVER extends ClientEventListener { + + @Override + public void call(Channel channel, String data) { + Map map = MapHelper.parser(data); + SimplePrinter.printNotice("\nPlayer " + map.get("winnerNickname") + "[" + map.get("winnerType") + "]" + " won the game"); + + if (map.containsKey("scores")){ + List> scores = Noson.convert(map.get("scores"), new NoType>>() {}); + for (Map score : scores) { + if (! Objects.equals(score.get("clientId"), SimpleClient.id)) { + SimplePrinter.printNotice(score.get("nickName").toString() + "'s rest poker is:"); + SimplePrinter.printPokers(Noson.convert(score.get("pokers"), new NoType>() {})); + } + } + SimplePrinter.printNotice("\n"); + // print score + for (Map score : scores) { + String scoreInc = score.get("scoreInc").toString(); + String scoreTotal = score.get("score").toString(); + if (SimpleClient.id != (int) score.get("clientId")) { + SimplePrinter.printNotice(score.get("nickName").toString() + "'s score is " + scoreInc + ", total score is " + scoreTotal); + } else { + SimplePrinter.printNotice("your score is " + scoreInc + ", total score is " + scoreTotal); + } + } + ClientEventListener_CODE_GAME_READY.gameReady(channel); + } + } +} diff --git a/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_GAME_POKER_PLAY.java b/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_GAME_POKER_PLAY.java new file mode 100644 index 0000000..063b815 --- /dev/null +++ b/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_GAME_POKER_PLAY.java @@ -0,0 +1,130 @@ +package org.nico.ratel.landlords.client.event; + +import io.netty.channel.Channel; +import org.nico.noson.Noson; +import org.nico.noson.entity.NoType; +import org.nico.ratel.landlords.client.SimpleClient; +import org.nico.ratel.landlords.client.entity.User; +import org.nico.ratel.landlords.entity.Poker; +import org.nico.ratel.landlords.entity.PokerSell; +import org.nico.ratel.landlords.enums.PokerLevel; +import org.nico.ratel.landlords.enums.ServerEventCode; +import org.nico.ratel.landlords.helper.MapHelper; +import org.nico.ratel.landlords.helper.PokerHelper; +import org.nico.ratel.landlords.print.SimplePrinter; +import org.nico.ratel.landlords.print.SimpleWriter; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public class ClientEventListener_CODE_GAME_POKER_PLAY extends ClientEventListener { + + @Override + public void call(Channel channel, String data) { + Map map = MapHelper.parser(data); + + SimplePrinter.printNotice("It's your turn to play, your cards are as follows: "); + List pokers = Noson.convert(map.get("pokers"), new NoType>() { + }); + SimplePrinter.printPokers(pokers); + SimplePrinter.printNotice("Last cards are"); + SimplePrinter.printNotice(map.containsKey("lastPokers")?map.get("lastPokers").toString():""); + + SimplePrinter.printNotice("Please enter the combination you came up with (enter [exit|e] to exit current room, enter [pass|p] to jump current round, enter [view|v] to show all valid combinations.)"); + String line = SimpleWriter.write(User.INSTANCE.getNickname(), "combination"); + + if (line == null) { + SimplePrinter.printNotice("Invalid enter"); + call(channel, data); + } else { + if (line.equalsIgnoreCase("pass") || line.equalsIgnoreCase("p")) { + pushToServer(channel, ServerEventCode.CODE_GAME_POKER_PLAY_PASS); + } else if (line.equalsIgnoreCase("exit") || line.equalsIgnoreCase("e")) { + pushToServer(channel, ServerEventCode.CODE_CLIENT_EXIT); + } else if (line.equalsIgnoreCase("view") || line.equalsIgnoreCase("v")) { + if (!map.containsKey("lastSellPokers") || !map.containsKey("lastSellClientId")) { + SimplePrinter.printNotice("Current server version unsupport this feature, need more than v1.2.4."); + call(channel, data); + return; + } + Object lastSellPokersObj = map.get("lastSellPokers"); + if (lastSellPokersObj == null || Integer.valueOf(SimpleClient.id).equals(map.get("lastSellClientId"))) { + SimplePrinter.printNotice("Up to you !"); + call(channel, data); + return; + } else { + List lastSellPokers = Noson.convert(lastSellPokersObj, new NoType>() {}); + List sells = PokerHelper.validSells(PokerHelper.checkPokerType(lastSellPokers), pokers); + if (sells.size() == 0) { + SimplePrinter.printNotice("It is a pity that, there is no winning combination..."); + call(channel, data); + return; + } + for (int i = 0; i < sells.size(); i++) { + SimplePrinter.printNotice(i + 1 + ". " + PokerHelper.textOnlyNoType(sells.get(i).getSellPokers())); + } + while (true) { + SimplePrinter.printNotice("You can enter index to choose anyone.(enter [back|b] to go back.)"); + line = SimpleWriter.write(User.INSTANCE.getNickname(), "choose"); + if (line.equalsIgnoreCase("back") || line.equalsIgnoreCase("b")) { + call(channel, data); + return; + } else { + try { + int choose = Integer.valueOf(line); + if (choose < 1 || choose > sells.size()) { + SimplePrinter.printNotice("The input number must be in the range of 1 to " + sells.size() + "."); + } else { + List choosePokers = sells.get(choose - 1).getSellPokers(); + List options = new ArrayList<>(); + for (Poker poker : choosePokers) { + options.add(poker.getLevel().getAlias()[0]); + } + pushToServer(channel, ServerEventCode.CODE_GAME_POKER_PLAY, Noson.reversal(options.toArray(new Character[]{}))); + break; + } + } catch (NumberFormatException e) { + SimplePrinter.printNotice("Please input a number."); + } + } + } + } + +// PokerHelper.validSells(lastPokerSell, pokers); + } else { + String[] strs = line.split(" "); + List options = new ArrayList<>(); + boolean access = true; + for (int index = 0; index < strs.length; index++) { + String str = strs[index]; + for (char c : str.toCharArray()) { + if (c == ' ' || c == '\t') { + } else { + if (!PokerLevel.aliasContains(c)) { + access = false; + break; + } else { + options.add(c); + } + } + } + } + if (access) { + pushToServer(channel, ServerEventCode.CODE_GAME_POKER_PLAY, Noson.reversal(options.toArray(new Character[]{}))); + } else { + SimplePrinter.printNotice("Invalid enter"); + + if (lastPokers != null) { + SimplePrinter.printNotice(lastSellClientNickname + "[" + lastSellClientType + "] played:"); + SimplePrinter.printPokers(lastPokers); + } + + call(channel, data); + } + } + } + + } + +} diff --git a/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_GAME_POKER_PLAY_CANT_PASS.java b/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_GAME_POKER_PLAY_CANT_PASS.java new file mode 100644 index 0000000..826f674 --- /dev/null +++ b/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_GAME_POKER_PLAY_CANT_PASS.java @@ -0,0 +1,16 @@ +package org.nico.ratel.landlords.client.event; + +import org.nico.ratel.landlords.enums.ServerEventCode; +import org.nico.ratel.landlords.print.SimplePrinter; + +import io.netty.channel.Channel; + +public class ClientEventListener_CODE_GAME_POKER_PLAY_CANT_PASS extends ClientEventListener { + + @Override + public void call(Channel channel, String data) { + SimplePrinter.printNotice("You played the previous card, so you can't pass."); + pushToServer(channel, ServerEventCode.CODE_GAME_POKER_PLAY_REDIRECT); + } + +} diff --git a/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_GAME_POKER_PLAY_INVALID.java b/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_GAME_POKER_PLAY_INVALID.java new file mode 100644 index 0000000..9a69aaa --- /dev/null +++ b/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_GAME_POKER_PLAY_INVALID.java @@ -0,0 +1,23 @@ +package org.nico.ratel.landlords.client.event; + +import org.nico.ratel.landlords.enums.ServerEventCode; +import org.nico.ratel.landlords.print.SimplePrinter; + +import io.netty.channel.Channel; + +public class ClientEventListener_CODE_GAME_POKER_PLAY_INVALID extends ClientEventListener { + + @Override + public void call(Channel channel, String data) { + + SimplePrinter.printNotice("This combination is invalid."); + + if(lastPokers != null) { + SimplePrinter.printNotice(lastSellClientNickname + "[" + lastSellClientType + "] played:"); + SimplePrinter.printPokers(lastPokers); + } + + pushToServer(channel, ServerEventCode.CODE_GAME_POKER_PLAY_REDIRECT); + } + +} diff --git a/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_GAME_POKER_PLAY_LESS.java b/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_GAME_POKER_PLAY_LESS.java new file mode 100644 index 0000000..4013c2d --- /dev/null +++ b/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_GAME_POKER_PLAY_LESS.java @@ -0,0 +1,22 @@ +package org.nico.ratel.landlords.client.event; + +import org.nico.ratel.landlords.enums.ServerEventCode; +import org.nico.ratel.landlords.print.SimplePrinter; + +import io.netty.channel.Channel; + +public class ClientEventListener_CODE_GAME_POKER_PLAY_LESS extends ClientEventListener { + + @Override + public void call(Channel channel, String data) { + SimplePrinter.printNotice("Your combination has lower rank than the previous. You cannot play this combination!"); + + if(lastPokers != null) { + SimplePrinter.printNotice(lastSellClientNickname + "[" + lastSellClientType + "] played:"); + SimplePrinter.printPokers(lastPokers); + } + + pushToServer(channel, ServerEventCode.CODE_GAME_POKER_PLAY_REDIRECT); + } + +} diff --git a/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_GAME_POKER_PLAY_MISMATCH.java b/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_GAME_POKER_PLAY_MISMATCH.java new file mode 100644 index 0000000..06bb1cb --- /dev/null +++ b/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_GAME_POKER_PLAY_MISMATCH.java @@ -0,0 +1,27 @@ +package org.nico.ratel.landlords.client.event; + +import java.util.Map; + +import org.nico.ratel.landlords.enums.ServerEventCode; +import org.nico.ratel.landlords.helper.MapHelper; +import org.nico.ratel.landlords.print.SimplePrinter; + +import io.netty.channel.Channel; + +public class ClientEventListener_CODE_GAME_POKER_PLAY_MISMATCH extends ClientEventListener { + + @Override + public void call(Channel channel, String data) { + Map map = MapHelper.parser(data); + + SimplePrinter.printNotice("Your combination is " + map.get("playType") + " (" + map.get("playCount") + "), but the previous combination is " + map.get("preType") + " (" + map.get("preCount") + "). Mismatch!"); + + if(lastPokers != null) { + SimplePrinter.printNotice(lastSellClientNickname + "[" + lastSellClientType + "] played:"); + SimplePrinter.printPokers(lastPokers); + } + + pushToServer(channel, ServerEventCode.CODE_GAME_POKER_PLAY_REDIRECT); + } + +} diff --git a/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_GAME_POKER_PLAY_ORDER_ERROR.java b/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_GAME_POKER_PLAY_ORDER_ERROR.java new file mode 100644 index 0000000..8c698a0 --- /dev/null +++ b/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_GAME_POKER_PLAY_ORDER_ERROR.java @@ -0,0 +1,15 @@ +package org.nico.ratel.landlords.client.event; + +import org.nico.ratel.landlords.print.SimplePrinter; + +import io.netty.channel.Channel; + +public class ClientEventListener_CODE_GAME_POKER_PLAY_ORDER_ERROR extends ClientEventListener { + + @Override + public void call(Channel channel, String data) { + + SimplePrinter.printNotice("It is not your turn yet. Please wait for other players!"); + } + +} diff --git a/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_GAME_POKER_PLAY_PASS.java b/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_GAME_POKER_PLAY_PASS.java new file mode 100644 index 0000000..c77db21 --- /dev/null +++ b/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_GAME_POKER_PLAY_PASS.java @@ -0,0 +1,26 @@ +package org.nico.ratel.landlords.client.event; + +import java.util.Map; + +import org.nico.ratel.landlords.client.SimpleClient; +import org.nico.ratel.landlords.enums.ServerEventCode; +import org.nico.ratel.landlords.helper.MapHelper; +import org.nico.ratel.landlords.print.SimplePrinter; + +import io.netty.channel.Channel; + +public class ClientEventListener_CODE_GAME_POKER_PLAY_PASS extends ClientEventListener { + + @Override + public void call(Channel channel, String data) { + Map map = MapHelper.parser(data); + + SimplePrinter.printNotice(map.get("clientNickname") + " passed. It is now " + map.get("nextClientNickname") + "'s turn."); + + int turnClientId = (int) map.get("nextClientId"); + if (SimpleClient.id == turnClientId) { + pushToServer(channel, ServerEventCode.CODE_GAME_POKER_PLAY_REDIRECT); + } + } + +} diff --git a/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_GAME_POKER_PLAY_REDIRECT.java b/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_GAME_POKER_PLAY_REDIRECT.java new file mode 100644 index 0000000..8cdafc3 --- /dev/null +++ b/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_GAME_POKER_PLAY_REDIRECT.java @@ -0,0 +1,48 @@ +package org.nico.ratel.landlords.client.event; + +import io.netty.channel.Channel; +import org.nico.ratel.landlords.client.SimpleClient; +import org.nico.ratel.landlords.enums.ClientEventCode; +import org.nico.ratel.landlords.helper.MapHelper; +import org.nico.ratel.landlords.print.FormatPrinter; +import org.nico.ratel.landlords.print.SimplePrinter; + +import java.util.List; +import java.util.Map; + +import static org.nico.ratel.landlords.client.event.ClientEventListener_CODE_CLIENT_NICKNAME_SET.NICKNAME_MAX_LENGTH; + +public class ClientEventListener_CODE_GAME_POKER_PLAY_REDIRECT extends ClientEventListener { + + private static String[] choose = new String[]{"UP", "DOWN"}; + + private static String format = "\n[%-4s] %-" + NICKNAME_MAX_LENGTH + "s surplus %-2s [%-8s]"; + + @SuppressWarnings("unchecked") + @Override + public void call(Channel channel, String data) { + + Map map = MapHelper.parser(data); + + int sellClientId = (int) map.get("sellClientId"); + + List> clientInfos = (List>) map.get("clientInfos"); + + for (int index = 0; index < 2; index++) { + for (Map clientInfo : clientInfos) { + String position = (String) clientInfo.get("position"); + if (position.equalsIgnoreCase(choose[index])) { + FormatPrinter.printNotice(format, clientInfo.get("position"), clientInfo.get("clientNickname"), clientInfo.get("surplus"), clientInfo.get("type")); + } + } + } + SimplePrinter.printNotice(""); + + if (sellClientId == SimpleClient.id) { + get(ClientEventCode.CODE_GAME_POKER_PLAY).call(channel, data); + } else { + SimplePrinter.printNotice("It is " + map.get("sellClientNickname") + "'s turn. Please wait for him to play his cards."); + } + } + +} diff --git a/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_GAME_READY.java b/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_GAME_READY.java new file mode 100644 index 0000000..cfe46f2 --- /dev/null +++ b/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_GAME_READY.java @@ -0,0 +1,34 @@ +package org.nico.ratel.landlords.client.event; + +import io.netty.channel.Channel; +import org.nico.ratel.landlords.channel.ChannelUtils; +import org.nico.ratel.landlords.client.SimpleClient; +import org.nico.ratel.landlords.client.entity.User; +import org.nico.ratel.landlords.enums.ServerEventCode; +import org.nico.ratel.landlords.helper.MapHelper; +import org.nico.ratel.landlords.print.SimplePrinter; +import org.nico.ratel.landlords.print.SimpleWriter; + +import java.util.Map; + +public class ClientEventListener_CODE_GAME_READY extends ClientEventListener { + @Override + public void call(Channel channel, String data) { + Map map = MapHelper.parser(data); + if (SimpleClient.id == (int) map.get("clientId")) { + SimplePrinter.printNotice("you are ready to play game."); + return; + } + SimplePrinter.printNotice(map.get("clientNickName").toString() + " is ready to play game."); + } + + static void gameReady(Channel channel) { + SimplePrinter.printNotice("\nDo you want to continue the game? [Y/N]"); + String line = SimpleWriter.write(User.INSTANCE.getNickname(), "notReady"); + if (line.equals("Y") || line.equals("y")) { + ChannelUtils.pushToServer(channel, ServerEventCode.CODE_GAME_READY, ""); + return; + } + ChannelUtils.pushToServer(channel, ServerEventCode.CODE_CLIENT_EXIT, ""); + } +} diff --git a/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_GAME_STARTING.java b/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_GAME_STARTING.java new file mode 100644 index 0000000..30ed8a8 --- /dev/null +++ b/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_GAME_STARTING.java @@ -0,0 +1,34 @@ +package org.nico.ratel.landlords.client.event; + +import io.netty.channel.Channel; +import org.nico.noson.Noson; +import org.nico.noson.entity.NoType; +import org.nico.ratel.landlords.entity.Poker; +import org.nico.ratel.landlords.enums.ClientEventCode; +import org.nico.ratel.landlords.helper.MapHelper; +import org.nico.ratel.landlords.print.SimplePrinter; + +import java.util.List; +import java.util.Map; + +public class ClientEventListener_CODE_GAME_STARTING extends ClientEventListener { + + @Override + public void call(Channel channel, String data) { + + Map map = MapHelper.parser(data); + + SimplePrinter.printNotice("Game starting!"); + + List pokers = Noson.convert(map.get("pokers"), new NoType>() {}); + + SimplePrinter.printNotice(""); + SimplePrinter.printNotice("Your cards are"); + SimplePrinter.printPokers(pokers); + SimplePrinter.printNotice("Last cards are"); + SimplePrinter.printNotice(map.containsKey("lastPokers")?map.get("lastPokers").toString():""); + + get(ClientEventCode.CODE_GAME_LANDLORD_ELECT).call(channel, data); + } + +} diff --git a/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_GAME_WATCH.java b/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_GAME_WATCH.java new file mode 100644 index 0000000..54dc969 --- /dev/null +++ b/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_GAME_WATCH.java @@ -0,0 +1,152 @@ +package org.nico.ratel.landlords.client.event; + +import io.netty.channel.Channel; +import org.nico.noson.Noson; +import org.nico.noson.entity.NoType; +import org.nico.ratel.landlords.client.entity.User; +import org.nico.ratel.landlords.entity.Poker; +import org.nico.ratel.landlords.enums.ClientEventCode; +import org.nico.ratel.landlords.helper.MapHelper; +import org.nico.ratel.landlords.print.SimplePrinter; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.List; +import java.util.Map; + +public class ClientEventListener_CODE_GAME_WATCH extends ClientEventListener { + + @Override + public void call(Channel channel, String wrapData) { + // 退出观战模式后不处理观战请求 + if (!User.INSTANCE.isWatching()) { + return; + } + + Map wrapMap = MapHelper.parser(wrapData); + ClientEventCode rawCode = ClientEventCode.valueOf(wrapMap.get("code").toString()); + Object rawData = wrapMap.get("data"); + + switch (rawCode) { + case CODE_ROOM_JOIN_SUCCESS: + printJoinPlayerInfo(rawData); + break; + + // 游戏开始 + case CODE_GAME_STARTING: + printGameStartInfo(rawData); + break; + + // 抢地主 + case CODE_GAME_LANDLORD_ELECT: + printRobLandlord(rawData); + break; + + // 地主确认 + case CODE_GAME_LANDLORD_CONFIRM: + printConfirmLandlord(rawData); + break; + + // 出牌 + case CODE_SHOW_POKERS: + printPlayPokers(rawData); + break; + + // 不出(过) + case CODE_GAME_POKER_PLAY_PASS: + printPlayPass(rawData); + break; + + // 玩家退出(此时可以退出观战,修改User.isWatching状态) + case CODE_CLIENT_EXIT: + printPlayerExit(rawData, channel); + break; + + // 玩家被提出房间 + case CODE_CLIENT_KICK: + printKickInfo(rawData); + break; + + // 游戏结束(此时可以退出观战,修改User.isWatching状态) + case CODE_GAME_OVER: + printGameResult(rawData, channel); + break; + + // 其他事件忽略 + default: + break; + } + } + + private void printJoinPlayerInfo(Object rawData) { + printNoticeWithTime("Player [" + rawData + "] joined the room"); + } + + private void printGameStartInfo(Object rawData) { + Map map = MapHelper.parser(rawData.toString()); + + printNoticeWithTime("Game starting"); + printNoticeWithTime("Player1 : " + map.get("player1")); + printNoticeWithTime("Player2 : " + map.get("player2")); + printNoticeWithTime("Player3 : " + map.get("player3")); + } + + private void printRobLandlord(Object rawData) { + printNoticeWithTime("Player [" + rawData + "] didn't choose to become the landlord."); + } + + private void printConfirmLandlord(Object rawData) { + Map map = MapHelper.parser(rawData.toString()); + + printNoticeWithTime("Player [" + map.get("landlord") + "] has become the landlord and gotten three extra cards:"); + SimplePrinter.printPokers(Noson.convert(map.get("additionalPokers"), new NoType>() {})); + } + + private void printPlayPokers(Object rawData) { + Map map = MapHelper.parser(rawData.toString()); + + printNoticeWithTime("Player [" + map.get("clientNickname") + "] played:"); + SimplePrinter.printPokers(Noson.convert(map.get("pokers"), new NoType>() {})); + } + + private void printPlayPass(Object rawData) { + printNoticeWithTime("Player [" + rawData + "] : passed"); + } + + private void printPlayerExit(Object rawData, Channel channel) { + printNoticeWithTime("Player [" + rawData + "] left the room"); + quitWatch(channel); + } + + private void quitWatch(Channel channel) { + printNoticeWithTime("This room will be closed!"); + printNoticeWithTime("Spectating ended. Bye."); + SimplePrinter.printNotice(""); + SimplePrinter.printNotice(""); + + // 修改玩家是否观战状态 + User.INSTANCE.setWatching(false); + + // 退出watch展示 + get(ClientEventCode.CODE_SHOW_OPTIONS).call(channel, ""); + } + + private void printGameResult(Object rawData, Channel channel) { + Map map = MapHelper.parser(rawData.toString()); + + printNoticeWithTime("Player [" + map.get("winnerNickname") + "](" + map.get("winnerType") + ") won the game."); + } + + private void printKickInfo(Object rawData) { + printNoticeWithTime("Player [" + rawData + "] has been kicked out for being idle."); + } + + + private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + + private void printNoticeWithTime(String notice) { + String msg = FORMATTER.format(LocalDateTime.now()) + " " + notice; + + SimplePrinter.printNotice(msg); + } +} diff --git a/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_GAME_WATCH_SUCCESSFUL.java b/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_GAME_WATCH_SUCCESSFUL.java new file mode 100644 index 0000000..7eca99f --- /dev/null +++ b/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_GAME_WATCH_SUCCESSFUL.java @@ -0,0 +1,71 @@ +package org.nico.ratel.landlords.client.event; + +import io.netty.channel.Channel; +import org.nico.noson.Noson; +import org.nico.ratel.landlords.client.entity.User; +import org.nico.ratel.landlords.enums.ClientEventCode; +import org.nico.ratel.landlords.enums.ServerEventCode; +import org.nico.ratel.landlords.helper.MapHelper; +import org.nico.ratel.landlords.print.SimplePrinter; +import org.nico.ratel.landlords.print.SimpleWriter; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.Map; + +public class ClientEventListener_CODE_GAME_WATCH_SUCCESSFUL extends ClientEventListener { + + private static final String WATCH_SUCCESSFUL_TIPS = " \n" + + "+------------------------------------------------\n" + + "|You are already watching the game. \n" + + "|Room owner: %s. Room current status: %s.\n" + + "+------------------------------------------------\n" + + "(Hint: enter [exit|e] to exit.) \n" + + " "; + + @Override + public void call(Channel channel, String data) { + // 修改User.isWatching状态 + // Edit User.isWatching + User.INSTANCE.setWatching(true); + + // 进入观战提示 + // Enter spectator mode + Map map = MapHelper.parser(data); + SimplePrinter.printNotice(String.format(WATCH_SUCCESSFUL_TIPS, map.get("owner"), map.get("status"))); + + // 监听输入用于退出 + // Listen enter event to exit spectator mode + new Thread(() -> registerExitEvent(channel), "exit-spectator-input-thread").start(); + } + + private void registerExitEvent(Channel channel) { + String enter = SimpleWriter.write(); + if ("exit".equalsIgnoreCase(enter) || "e".equalsIgnoreCase(enter)) { + quitWatch(channel); + return; + } + + printCommandUsage(); + registerExitEvent(channel); + } + + private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + + private void quitWatch(Channel channel) { + SimplePrinter.printNotice(FORMATTER.format(LocalDateTime.now()) + " Spectating ended. Bye."); + SimplePrinter.printNotice(""); + SimplePrinter.printNotice(""); + + // 修改玩家是否观战状态 + User.INSTANCE.setWatching(false); + + // 退出观战模式 + pushToServer(channel, ServerEventCode.CODE_GAME_WATCH_EXIT); + get(ClientEventCode.CODE_SHOW_OPTIONS).call(channel, ""); + } + + private void printCommandUsage() { + SimplePrinter.printNotice("Enter [exit|e] to exit"); + } +} diff --git a/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_PVE_DIFFICULTY_NOT_SUPPORT.java b/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_PVE_DIFFICULTY_NOT_SUPPORT.java new file mode 100644 index 0000000..d7d0b74 --- /dev/null +++ b/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_PVE_DIFFICULTY_NOT_SUPPORT.java @@ -0,0 +1,17 @@ +package org.nico.ratel.landlords.client.event; + +import org.nico.ratel.landlords.enums.ClientEventCode; +import org.nico.ratel.landlords.print.SimplePrinter; + +import io.netty.channel.Channel; + +public class ClientEventListener_CODE_PVE_DIFFICULTY_NOT_SUPPORT extends ClientEventListener { + + @Override + public void call(Channel channel, String data) { + SimplePrinter.printNotice("The current difficulty is not supported, please pay attention to the following.\n"); + get(ClientEventCode.CODE_SHOW_OPTIONS_PVE).call(channel, data); + } + + +} diff --git a/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_ROOM_CREATE_SUCCESS.java b/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_ROOM_CREATE_SUCCESS.java new file mode 100644 index 0000000..6bd8b6e --- /dev/null +++ b/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_ROOM_CREATE_SUCCESS.java @@ -0,0 +1,19 @@ +package org.nico.ratel.landlords.client.event; + +import org.nico.noson.Noson; +import org.nico.ratel.landlords.entity.Room; +import org.nico.ratel.landlords.print.SimplePrinter; + +import io.netty.channel.Channel; + +public class ClientEventListener_CODE_ROOM_CREATE_SUCCESS extends ClientEventListener { + + @Override + public void call(Channel channel, String data) { + Room room = Noson.convert(data, Room.class); + initLastSellInfo(); + SimplePrinter.printNotice("You have created a room with id " + room.getId()); + SimplePrinter.printNotice("Please wait for other players to join !"); + } + +} diff --git a/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_ROOM_JOIN_FAIL_BY_FULL.java b/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_ROOM_JOIN_FAIL_BY_FULL.java new file mode 100644 index 0000000..bf5668f --- /dev/null +++ b/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_ROOM_JOIN_FAIL_BY_FULL.java @@ -0,0 +1,22 @@ +package org.nico.ratel.landlords.client.event; + +import java.util.Map; + +import org.nico.ratel.landlords.enums.ClientEventCode; +import org.nico.ratel.landlords.helper.MapHelper; +import org.nico.ratel.landlords.print.SimplePrinter; + +import io.netty.channel.Channel; + +public class ClientEventListener_CODE_ROOM_JOIN_FAIL_BY_FULL extends ClientEventListener { + + @Override + public void call(Channel channel, String data) { + Map dataMap = MapHelper.parser(data); + + SimplePrinter.printNotice("Join room failed. Room " + dataMap.get("roomId") + " is full!"); + ClientEventListener.get(ClientEventCode.CODE_SHOW_OPTIONS).call(channel, data); + } + + +} diff --git a/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_ROOM_JOIN_FAIL_BY_INEXIST.java b/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_ROOM_JOIN_FAIL_BY_INEXIST.java new file mode 100644 index 0000000..c501153 --- /dev/null +++ b/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_ROOM_JOIN_FAIL_BY_INEXIST.java @@ -0,0 +1,20 @@ +package org.nico.ratel.landlords.client.event; + +import java.util.Map; + +import org.nico.ratel.landlords.enums.ClientEventCode; +import org.nico.ratel.landlords.helper.MapHelper; +import org.nico.ratel.landlords.print.SimplePrinter; + +import io.netty.channel.Channel; + +public class ClientEventListener_CODE_ROOM_JOIN_FAIL_BY_INEXIST extends ClientEventListener { + + @Override + public void call(Channel channel, String data) { + Map dataMap = MapHelper.parser(data); + + SimplePrinter.printNotice("Join room failed. Room " + dataMap.get("roomId") + " doesn't exist!"); + ClientEventListener.get(ClientEventCode.CODE_SHOW_OPTIONS).call(channel, data); + } +} diff --git a/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_ROOM_JOIN_SUCCESS.java b/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_ROOM_JOIN_SUCCESS.java new file mode 100644 index 0000000..3c4509d --- /dev/null +++ b/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_ROOM_JOIN_SUCCESS.java @@ -0,0 +1,28 @@ +package org.nico.ratel.landlords.client.event; + +import java.util.Map; + +import org.nico.ratel.landlords.client.SimpleClient; +import org.nico.ratel.landlords.helper.MapHelper; +import org.nico.ratel.landlords.print.SimplePrinter; + +import io.netty.channel.Channel; + +public class ClientEventListener_CODE_ROOM_JOIN_SUCCESS extends ClientEventListener { + + @Override + public void call(Channel channel, String data) { + Map map = MapHelper.parser(data); + + initLastSellInfo(); + + int joinClientId = (int) map.get("clientId"); + if (SimpleClient.id == joinClientId) { + SimplePrinter.printNotice("You have joined room:" + map.get("roomId") + ". There are " + map.get("roomClientCount") + " players in the room now."); + SimplePrinter.printNotice("Please wait for other players to join. The game would start at three players!"); + } else { + SimplePrinter.printNotice(map.get("clientNickname") + " joined room, there are currently " + map.get("roomClientCount") + " in the room."); + } + + } +} diff --git a/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_ROOM_PLAY_FAIL_BY_INEXIST.java b/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_ROOM_PLAY_FAIL_BY_INEXIST.java new file mode 100644 index 0000000..97d994a --- /dev/null +++ b/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_ROOM_PLAY_FAIL_BY_INEXIST.java @@ -0,0 +1,18 @@ +package org.nico.ratel.landlords.client.event; + +import org.nico.ratel.landlords.enums.ClientEventCode; +import org.nico.ratel.landlords.print.SimplePrinter; + +import io.netty.channel.Channel; + +public class ClientEventListener_CODE_ROOM_PLAY_FAIL_BY_INEXIST extends ClientEventListener { + + @Override + public void call(Channel channel, String data) { + + SimplePrinter.printNotice("Play failed. Room already disbanded!"); + ClientEventListener.get(ClientEventCode.CODE_SHOW_OPTIONS).call(channel, data); + } + + +} diff --git a/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_SHOW_OPTIONS.java b/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_SHOW_OPTIONS.java new file mode 100644 index 0000000..faaa539 --- /dev/null +++ b/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_SHOW_OPTIONS.java @@ -0,0 +1,38 @@ +package org.nico.ratel.landlords.client.event; + +import org.nico.ratel.landlords.client.entity.User; +import org.nico.ratel.landlords.enums.ClientEventCode; +import org.nico.ratel.landlords.print.SimplePrinter; +import org.nico.ratel.landlords.print.SimpleWriter; +import org.nico.ratel.landlords.utils.OptionsUtils; + +import io.netty.channel.Channel; + +public class ClientEventListener_CODE_SHOW_OPTIONS extends ClientEventListener { + + @Override + public void call(Channel channel, String data) { + SimplePrinter.printNotice("Options: "); + SimplePrinter.printNotice("1. PvP"); + SimplePrinter.printNotice("2. PvE"); + SimplePrinter.printNotice("3. Settings"); + SimplePrinter.printNotice("Please select an option above (enter [exit|e] to log out)"); + String line = SimpleWriter.write(User.INSTANCE.getNickname(), "selection"); + + if(line.equalsIgnoreCase("exit") || line.equalsIgnoreCase("e")) { + System.exit(0); + } else { + int choose = OptionsUtils.getOptions(line); + if (choose == 1) { + get(ClientEventCode.CODE_SHOW_OPTIONS_PVP).call(channel, data); + } else if (choose == 2) { + get(ClientEventCode.CODE_SHOW_OPTIONS_PVE).call(channel, data); + } else if (choose == 3) { + get(ClientEventCode.CODE_SHOW_OPTIONS_SETTING).call(channel, data); + } else { + SimplePrinter.printNotice("Invalid option, please choose again:"); + call(channel, data); + } + } + } +} diff --git a/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_SHOW_OPTIONS_PVE.java b/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_SHOW_OPTIONS_PVE.java new file mode 100644 index 0000000..5fef220 --- /dev/null +++ b/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_SHOW_OPTIONS_PVE.java @@ -0,0 +1,38 @@ +package org.nico.ratel.landlords.client.event; + +import org.nico.ratel.landlords.client.entity.User; +import org.nico.ratel.landlords.enums.ClientEventCode; +import org.nico.ratel.landlords.enums.ServerEventCode; +import org.nico.ratel.landlords.print.SimplePrinter; +import org.nico.ratel.landlords.print.SimpleWriter; +import org.nico.ratel.landlords.utils.OptionsUtils; + +import io.netty.channel.Channel; + +public class ClientEventListener_CODE_SHOW_OPTIONS_PVE extends ClientEventListener { + + @Override + public void call(Channel channel, String data) { + SimplePrinter.printNotice("PVE: "); + SimplePrinter.printNotice("1. Easy Mode"); + SimplePrinter.printNotice("2. Medium Mode"); + SimplePrinter.printNotice("3. Hard Mode"); + SimplePrinter.printNotice("Please select an option above (enter [back|b] to return to options list)"); + String line = SimpleWriter.write(User.INSTANCE.getNickname(), "pve"); + + if(line.equalsIgnoreCase("back") || line.equalsIgnoreCase("b")) { + get(ClientEventCode.CODE_SHOW_OPTIONS).call(channel, data); + return; + } + + int choose = OptionsUtils.getOptions(line); + + if (choose < 0 || choose >= 4) { + SimplePrinter.printNotice("Invalid option, please choose again:"); + call(channel, data); + return; + } + initLastSellInfo(); + pushToServer(channel, ServerEventCode.CODE_ROOM_CREATE_PVE, String.valueOf(choose)); + } +} diff --git a/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_SHOW_OPTIONS_PVP.java b/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_SHOW_OPTIONS_PVP.java new file mode 100644 index 0000000..f52ade3 --- /dev/null +++ b/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_SHOW_OPTIONS_PVP.java @@ -0,0 +1,86 @@ +package org.nico.ratel.landlords.client.event; + +import org.nico.ratel.landlords.client.entity.User; +import org.nico.ratel.landlords.enums.ClientEventCode; +import org.nico.ratel.landlords.enums.ServerEventCode; +import org.nico.ratel.landlords.print.SimplePrinter; +import org.nico.ratel.landlords.print.SimpleWriter; +import org.nico.ratel.landlords.utils.OptionsUtils; + +import io.netty.channel.Channel; + +public class ClientEventListener_CODE_SHOW_OPTIONS_PVP extends ClientEventListener { + + @Override + public void call(Channel channel, String data) { + SimplePrinter.printNotice("PVP: "); + SimplePrinter.printNotice("1. Create Room"); + SimplePrinter.printNotice("2. Room List"); + SimplePrinter.printNotice("3. Join Room"); + SimplePrinter.printNotice("4. Spectate Game"); + SimplePrinter.printNotice("Please select an option above (enter [back|b] to return to options list)"); + String line = SimpleWriter.write(User.INSTANCE.getNickname(), "pvp"); + if (line == null) { + SimplePrinter.printNotice("Invalid options, please choose again:"); + call(channel, data); + return; + } + + if (line.equalsIgnoreCase("BACK") || line.equalsIgnoreCase("b")) { + get(ClientEventCode.CODE_SHOW_OPTIONS).call(channel, data); + return; + } + + int choose = OptionsUtils.getOptions(line); + switch (choose) { + case 1: + pushToServer(channel, ServerEventCode.CODE_ROOM_CREATE, null); + break; + case 2: + pushToServer(channel, ServerEventCode.CODE_GET_ROOMS, null); + break; + case 3: + handleJoinRoom(channel, data); + break; + case 4: + handleJoinRoom(channel, data, true); + break; + default: + SimplePrinter.printNotice("Invalid option, please choose again:"); + call(channel, data); + } + } + + private void parseInvalid(Channel channel, String data) { + SimplePrinter.printNotice("Invalid options, please choose again:"); + call(channel, data); + } + + private void handleJoinRoom(Channel channel, String data) { + handleJoinRoom(channel, data, false); + } + + private void handleJoinRoom(Channel channel, String data, Boolean watchMode) { + String notice = String.format("Please enter the room id you want to %s (enter [back|b] return options list)", watchMode ? "spectate" : "join"); + + SimplePrinter.printNotice(notice); + String line = SimpleWriter.write(User.INSTANCE.getNickname(), "roomid"); + if (line == null) { + parseInvalid(channel, data); + return; + } + + if (line.equalsIgnoreCase("BACK") || line.equalsIgnoreCase("b")) { + call(channel, data); + return; + } + + int option = OptionsUtils.getOptions(line); + if (option < 1) { + parseInvalid(channel, data); + return; + } + + pushToServer(channel, watchMode? ServerEventCode.CODE_GAME_WATCH : ServerEventCode.CODE_ROOM_JOIN, String.valueOf(option)); + } +} diff --git a/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_SHOW_OPTIONS_SETTING.java b/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_SHOW_OPTIONS_SETTING.java new file mode 100644 index 0000000..dfdb24b --- /dev/null +++ b/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_SHOW_OPTIONS_SETTING.java @@ -0,0 +1,42 @@ +package org.nico.ratel.landlords.client.event; + +import org.nico.ratel.landlords.client.entity.User; +import org.nico.ratel.landlords.enums.ClientEventCode; +import org.nico.ratel.landlords.helper.PokerHelper; +import org.nico.ratel.landlords.print.SimplePrinter; +import org.nico.ratel.landlords.print.SimpleWriter; +import org.nico.ratel.landlords.utils.OptionsUtils; + +import io.netty.channel.Channel; + +public class ClientEventListener_CODE_SHOW_OPTIONS_SETTING extends ClientEventListener { + + @Override + public void call(Channel channel, String data) { + SimplePrinter.printNotice("Setting: "); + SimplePrinter.printNotice("1. Card with shape edges (Default)"); + SimplePrinter.printNotice("2. Card with rounded edges"); + SimplePrinter.printNotice("3. Text Only with types"); + SimplePrinter.printNotice("4. Text Only without types"); + SimplePrinter.printNotice("5. Unicode Cards"); + + SimplePrinter.printNotice("Please select an option above (enter [BACK] to return to options list)"); + String line = SimpleWriter.write(User.INSTANCE.getNickname(), "setting"); + + if (line.equalsIgnoreCase("BACK")) { + get(ClientEventCode.CODE_SHOW_OPTIONS).call(channel, data); + } else { + int choose = OptionsUtils.getOptions(line); + + if (choose >= 1 && choose <= 5) { + PokerHelper.pokerPrinterType = choose - 1; + get(ClientEventCode.CODE_SHOW_OPTIONS).call(channel, data); + } else { + SimplePrinter.printNotice("Invalid setting, please choose again:"); + call(channel, data); + } + } + } + + +} diff --git a/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_SHOW_POKERS.java b/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_SHOW_POKERS.java new file mode 100644 index 0000000..9459523 --- /dev/null +++ b/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_SHOW_POKERS.java @@ -0,0 +1,33 @@ +package org.nico.ratel.landlords.client.event; + +import java.util.List; +import java.util.Map; + +import org.nico.noson.Noson; +import org.nico.noson.entity.NoType; +import org.nico.ratel.landlords.entity.Poker; +import org.nico.ratel.landlords.helper.MapHelper; +import org.nico.ratel.landlords.print.SimplePrinter; + +import io.netty.channel.Channel; + +public class ClientEventListener_CODE_SHOW_POKERS extends ClientEventListener { + + @Override + public void call(Channel channel, String data) { + + Map map = MapHelper.parser(data); + + lastSellClientNickname = (String) map.get("clientNickname"); + lastSellClientType = (String) map.get("clientType"); + + SimplePrinter.printNotice(lastSellClientNickname + "[" + lastSellClientType + "] played:"); + lastPokers = Noson.convert(map.get("pokers"), new NoType>() {}); + SimplePrinter.printPokers(lastPokers); + + if (map.containsKey("sellClientNickname")) { + SimplePrinter.printNotice("Next player is " + map.get("sellClientNickname") + ". Please wait for him to play his combination."); + } + } + +} diff --git a/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_SHOW_ROOMS.java b/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_SHOW_ROOMS.java new file mode 100644 index 0000000..29490ea --- /dev/null +++ b/landlords-client/src/main/java/org/nico/ratel/landlords/client/event/ClientEventListener_CODE_SHOW_ROOMS.java @@ -0,0 +1,35 @@ +package org.nico.ratel.landlords.client.event; + +import static org.nico.ratel.landlords.client.event.ClientEventListener_CODE_CLIENT_NICKNAME_SET.NICKNAME_MAX_LENGTH; +import java.util.List; +import java.util.Map; + +import org.nico.noson.Noson; +import org.nico.noson.entity.NoType; +import org.nico.ratel.landlords.enums.ClientEventCode; +import org.nico.ratel.landlords.print.FormatPrinter; +import org.nico.ratel.landlords.print.SimplePrinter; + +import io.netty.channel.Channel; + +public class ClientEventListener_CODE_SHOW_ROOMS extends ClientEventListener { + + @Override + public void call(Channel channel, String data) { + + List> roomList = Noson.convert(data, new NoType>>() {}); + if (roomList != null && !roomList.isEmpty()) { + // "COUNT" begins after NICKNAME_MAX_LENGTH characters. The dash means that the string is left-justified. + String format = "#\t%s\t|\t%-" + NICKNAME_MAX_LENGTH + "s\t|\t%-6s\t|\t%-6s\t#\n"; + FormatPrinter.printNotice(format, "ID", "OWNER", "COUNT", "TYPE"); + for (Map room : roomList) { + FormatPrinter.printNotice(format, room.get("roomId"), room.get("roomOwner"), room.get("roomClientCount"), room.get("roomType")); + } + SimplePrinter.printNotice(""); + get(ClientEventCode.CODE_SHOW_OPTIONS_PVP).call(channel, data); + } else { + SimplePrinter.printNotice("No available room. Please create a room!"); + get(ClientEventCode.CODE_SHOW_OPTIONS_PVP).call(channel, data); + } + } +} diff --git a/landlords-client/src/main/java/org/nico/ratel/landlords/client/handler/ProtobufTransferHandler.java b/landlords-client/src/main/java/org/nico/ratel/landlords/client/handler/ProtobufTransferHandler.java new file mode 100644 index 0000000..c392920 --- /dev/null +++ b/landlords-client/src/main/java/org/nico/ratel/landlords/client/handler/ProtobufTransferHandler.java @@ -0,0 +1,61 @@ +package org.nico.ratel.landlords.client.handler; + +import org.nico.noson.Noson; +import org.nico.ratel.landlords.channel.ChannelUtils; +import org.nico.ratel.landlords.client.entity.User; +import org.nico.ratel.landlords.client.event.ClientEventListener; +import org.nico.ratel.landlords.entity.ClientTransferData.ClientTransferDataProtoc; +import org.nico.ratel.landlords.enums.ClientEventCode; +import org.nico.ratel.landlords.enums.ServerEventCode; +import org.nico.ratel.landlords.print.SimplePrinter; + +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.handler.timeout.IdleState; +import io.netty.handler.timeout.IdleStateEvent; + +import java.util.HashMap; +import java.util.Map; + +public class ProtobufTransferHandler extends ChannelInboundHandlerAdapter { + + @Override + public void channelRead(ChannelHandlerContext ctx, Object msg) { + + if (msg instanceof ClientTransferDataProtoc) { + ClientTransferDataProtoc clientTransferData = (ClientTransferDataProtoc) msg; + if (!clientTransferData.getInfo().isEmpty()) { + SimplePrinter.printNotice(clientTransferData.getInfo()); + } + ClientEventCode code = ClientEventCode.valueOf(clientTransferData.getCode()); + if (User.INSTANCE.isWatching()) { + Map wrapMap = new HashMap<>(3); + wrapMap.put("code", code); + wrapMap.put("data", clientTransferData.getData()); + + ClientEventListener.get(ClientEventCode.CODE_GAME_WATCH).call(ctx.channel(), Noson.reversal(wrapMap)); + } else { + ClientEventListener.get(code).call(ctx.channel(), clientTransferData.getData()); + } + } + } + + @Override + public void userEventTriggered(ChannelHandlerContext ctx, Object evt) { + if (evt instanceof IdleStateEvent) { + IdleStateEvent event = (IdleStateEvent) evt; + if (event.state() == IdleState.WRITER_IDLE) { + ChannelUtils.pushToServer(ctx.channel(), ServerEventCode.CODE_CLIENT_HEAD_BEAT, "heartbeat"); + } + } + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { + if (cause instanceof java.io.IOException) { + SimplePrinter.printNotice("The network is not good or did not operate for a long time, has been offline"); + System.exit(0); + } + } + +} diff --git a/landlords-client/src/main/java/org/nico/ratel/landlords/client/handler/SecondProtobufCodec.java b/landlords-client/src/main/java/org/nico/ratel/landlords/client/handler/SecondProtobufCodec.java new file mode 100644 index 0000000..7f2c968 --- /dev/null +++ b/landlords-client/src/main/java/org/nico/ratel/landlords/client/handler/SecondProtobufCodec.java @@ -0,0 +1,24 @@ +package org.nico.ratel.landlords.client.handler; + +import java.util.List; + +import org.nico.ratel.landlords.entity.ClientTransferData.ClientTransferDataProtoc; + +import com.google.protobuf.MessageLite; + +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.MessageToMessageCodec; + +public class SecondProtobufCodec extends MessageToMessageCodec { + + @Override + protected void encode(ChannelHandlerContext ctx, MessageLite msg, List out) { + out.add(msg); + } + + @Override + protected void decode(ChannelHandlerContext ctx, ClientTransferDataProtoc msg, List out) { + out.add(msg); + } + +} diff --git a/landlords-client/src/main/java/org/nico/ratel/landlords/client/handler/WebsocketTransferHandler.java b/landlords-client/src/main/java/org/nico/ratel/landlords/client/handler/WebsocketTransferHandler.java new file mode 100644 index 0000000..7ef295b --- /dev/null +++ b/landlords-client/src/main/java/org/nico/ratel/landlords/client/handler/WebsocketTransferHandler.java @@ -0,0 +1,62 @@ +package org.nico.ratel.landlords.client.handler; + +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.channel.SimpleChannelInboundHandler; +import io.netty.handler.codec.http.websocketx.*; +import io.netty.handler.timeout.IdleState; +import io.netty.handler.timeout.IdleStateEvent; +import org.nico.noson.Noson; +import org.nico.ratel.landlords.channel.ChannelUtils; +import org.nico.ratel.landlords.client.entity.User; +import org.nico.ratel.landlords.client.event.ClientEventListener; +import org.nico.ratel.landlords.entity.ClientTransferData.ClientTransferDataProtoc; +import org.nico.ratel.landlords.entity.Msg; +import org.nico.ratel.landlords.enums.ClientEventCode; +import org.nico.ratel.landlords.enums.ServerEventCode; +import org.nico.ratel.landlords.print.SimplePrinter; +import org.nico.ratel.landlords.utils.JsonUtils; + +import java.util.HashMap; +import java.util.Map; + +public class WebsocketTransferHandler extends SimpleChannelInboundHandler { + + @Override + protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame frame) { + Msg msg = JsonUtils.fromJson(frame.text(), Msg.class); + if(msg.getInfo() != null && ! msg.getInfo().isEmpty()) { + SimplePrinter.printNotice(msg.getInfo()); + } + ClientEventCode code = ClientEventCode.valueOf(msg.getCode()); + if (User.INSTANCE.isWatching()) { + Map wrapMap = new HashMap<>(3); + wrapMap.put("code", code); + wrapMap.put("data", msg.getData()); + + ClientEventListener.get(ClientEventCode.CODE_GAME_WATCH).call(ctx.channel(), JsonUtils.toJson(wrapMap)); + } else { + ClientEventListener.get(code).call(ctx.channel(), msg.getData()); + } + } + + @Override + public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { + if (evt instanceof IdleStateEvent) { + IdleStateEvent event = (IdleStateEvent) evt; + if (event.state() == IdleState.WRITER_IDLE) { + ChannelUtils.pushToServer(ctx.channel(), ServerEventCode.CODE_CLIENT_HEAD_BEAT, "heartbeat"); + } + } + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { + if(cause instanceof java.io.IOException) { + SimplePrinter.printNotice("The network is not good or did not operate for a long time, has been offline"); + System.exit(0); + } + } + +} diff --git a/landlords-client/src/main/java/org/nico/ratel/landlords/client/proxy/ProtobufProxy.java b/landlords-client/src/main/java/org/nico/ratel/landlords/client/proxy/ProtobufProxy.java new file mode 100644 index 0000000..3116c59 --- /dev/null +++ b/landlords-client/src/main/java/org/nico/ratel/landlords/client/proxy/ProtobufProxy.java @@ -0,0 +1,50 @@ +package org.nico.ratel.landlords.client.proxy; + +import io.netty.bootstrap.Bootstrap; +import io.netty.channel.Channel; +import io.netty.channel.ChannelInitializer; +import io.netty.channel.EventLoopGroup; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.channel.socket.SocketChannel; +import io.netty.channel.socket.nio.NioSocketChannel; +import io.netty.handler.codec.protobuf.ProtobufDecoder; +import io.netty.handler.codec.protobuf.ProtobufEncoder; +import io.netty.handler.codec.protobuf.ProtobufVarint32FrameDecoder; +import io.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender; +import io.netty.handler.timeout.IdleStateHandler; +import org.nico.ratel.landlords.client.handler.ProtobufTransferHandler; +import org.nico.ratel.landlords.client.handler.SecondProtobufCodec; +import org.nico.ratel.landlords.entity.ClientTransferData; +import org.nico.ratel.landlords.print.SimplePrinter; + +import java.util.concurrent.TimeUnit; + +public class ProtobufProxy implements Proxy { + @Override + public void connect(String serverAddress, int port) throws InterruptedException { + EventLoopGroup group = new NioEventLoopGroup(); + try { + Bootstrap bootstrap = new Bootstrap() + .group(group) + .channel(NioSocketChannel.class) + .handler(new ChannelInitializer() { + @Override + protected void initChannel(SocketChannel ch) throws Exception { + ch.pipeline() + .addLast(new IdleStateHandler(0, 4, 0, TimeUnit.SECONDS)) + .addLast(new ProtobufVarint32FrameDecoder()) + .addLast(new ProtobufDecoder(ClientTransferData.ClientTransferDataProtoc.getDefaultInstance())) + .addLast(new ProtobufVarint32LengthFieldPrepender()) + .addLast(new ProtobufEncoder()) + .addLast(new SecondProtobufCodec()) + .addLast(new ProtobufTransferHandler()); + } + }); + SimplePrinter.printNotice("Connecting to " + serverAddress + ":" + port); + Channel channel = bootstrap.connect(serverAddress, port).sync().channel(); + channel.closeFuture().sync(); + } finally { + group.shutdownGracefully().sync(); + } + } +} diff --git a/landlords-client/src/main/java/org/nico/ratel/landlords/client/proxy/Proxy.java b/landlords-client/src/main/java/org/nico/ratel/landlords/client/proxy/Proxy.java new file mode 100644 index 0000000..1cbb72a --- /dev/null +++ b/landlords-client/src/main/java/org/nico/ratel/landlords/client/proxy/Proxy.java @@ -0,0 +1,8 @@ +package org.nico.ratel.landlords.client.proxy; + +import java.net.URISyntaxException; + +public interface Proxy { + + void connect(String serverAddress, int port) throws InterruptedException, URISyntaxException; +} diff --git a/landlords-client/src/main/java/org/nico/ratel/landlords/client/proxy/WebsocketProxy.java b/landlords-client/src/main/java/org/nico/ratel/landlords/client/proxy/WebsocketProxy.java new file mode 100644 index 0000000..a0962e4 --- /dev/null +++ b/landlords-client/src/main/java/org/nico/ratel/landlords/client/proxy/WebsocketProxy.java @@ -0,0 +1,61 @@ +package org.nico.ratel.landlords.client.proxy; + +import io.netty.bootstrap.Bootstrap; +import io.netty.channel.Channel; +import io.netty.channel.ChannelInitializer; +import io.netty.channel.EventLoopGroup; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.channel.socket.SocketChannel; +import io.netty.channel.socket.nio.NioSocketChannel; +import io.netty.handler.codec.http.*; +import io.netty.handler.codec.http.websocketx.*; +import io.netty.handler.codec.protobuf.ProtobufDecoder; +import io.netty.handler.codec.protobuf.ProtobufEncoder; +import io.netty.handler.codec.protobuf.ProtobufVarint32FrameDecoder; +import io.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender; +import io.netty.handler.codec.string.StringDecoder; +import io.netty.handler.codec.string.StringEncoder; +import io.netty.handler.stream.ChunkedWriteHandler; +import io.netty.handler.timeout.IdleStateHandler; +import org.nico.ratel.landlords.client.handler.SecondProtobufCodec; +import org.nico.ratel.landlords.client.handler.ProtobufTransferHandler; +import org.nico.ratel.landlords.client.handler.WebsocketTransferHandler; +import org.nico.ratel.landlords.entity.ClientTransferData; +import org.nico.ratel.landlords.print.SimplePrinter; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.concurrent.TimeUnit; + +public class WebsocketProxy implements Proxy{ + @Override + public void connect(String serverAddress, int port) throws InterruptedException, URISyntaxException { + URI uri = new URI("ws://" + serverAddress + ":" + port + "/ratel"); + EventLoopGroup group = new NioEventLoopGroup(); + try { + Bootstrap bootstrap = new Bootstrap() + .group(group) + .channel(NioSocketChannel.class) + .handler(new ChannelInitializer() { + @Override + protected void initChannel(SocketChannel ch) throws Exception { + ch.pipeline() + .addLast(new IdleStateHandler(60 * 30, 0, 0, TimeUnit.SECONDS)) + .addLast(new HttpClientCodec()) + .addLast(new HttpObjectAggregator(8192)) + .addLast(new WebSocketClientProtocolHandler(uri + , WebSocketVersion.V13 + , null + , true + , new DefaultHttpHeaders(), 100000)) + .addLast("ws", new WebsocketTransferHandler()); + } + }); + SimplePrinter.printNotice("Connecting to " + serverAddress + ":" + port); + Channel channel = bootstrap.connect(serverAddress, port).sync().channel(); + channel.closeFuture().sync(); + } finally { + group.shutdownGracefully().sync(); + } + } +} diff --git a/landlords-common/pom.xml b/landlords-common/pom.xml new file mode 100644 index 0000000..b171d10 --- /dev/null +++ b/landlords-common/pom.xml @@ -0,0 +1,16 @@ + + + 4.0.0 + landlords-common + landlords-common + This is a console version of the fight landlord game + + + com.smallnico.ratel + landlords + 1.4.0 + + + \ No newline at end of file diff --git a/landlords-common/src/main/java/org/nico/ratel/landlords/channel/ChannelUtils.java b/landlords-common/src/main/java/org/nico/ratel/landlords/channel/ChannelUtils.java new file mode 100644 index 0000000..33f5679 --- /dev/null +++ b/landlords-common/src/main/java/org/nico/ratel/landlords/channel/ChannelUtils.java @@ -0,0 +1,62 @@ +package org.nico.ratel.landlords.channel; + +import org.nico.ratel.landlords.entity.ClientTransferData; +import org.nico.ratel.landlords.entity.Msg; +import org.nico.ratel.landlords.entity.ServerTransferData; +import org.nico.ratel.landlords.enums.ClientEventCode; +import org.nico.ratel.landlords.enums.ServerEventCode; +import org.nico.ratel.landlords.utils.JsonUtils; + +import io.netty.channel.Channel; +import io.netty.channel.ChannelFuture; +import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; + +public class ChannelUtils { + + public static void pushToClient(Channel channel, ClientEventCode code, String data) { + pushToClient(channel, code, data, null); + } + + public static void pushToClient(Channel channel, ClientEventCode code, String data, String info) { + if (channel != null) { + if (channel.pipeline().get("ws") != null) { + Msg msg = new Msg(); + msg.setCode(code.toString()); + msg.setData(data); + msg.setInfo(info); + channel.writeAndFlush(new TextWebSocketFrame(JsonUtils.toJson(msg))); + } else { + ClientTransferData.ClientTransferDataProtoc.Builder clientTransferData = ClientTransferData.ClientTransferDataProtoc.newBuilder(); + if (code != null) { + clientTransferData.setCode(code.toString()); + } + if (data != null) { + clientTransferData.setData(data); + } + if (info != null) { + clientTransferData.setInfo(info); + } + channel.writeAndFlush(clientTransferData); + } + } + } + + public static ChannelFuture pushToServer(Channel channel, ServerEventCode code, String data) { + if (channel.pipeline().get("ws") != null) { + Msg msg = new Msg(); + msg.setCode(code.toString()); + msg.setData(data); + return channel.writeAndFlush(new TextWebSocketFrame(JsonUtils.toJson(msg))); + } else { + ServerTransferData.ServerTransferDataProtoc.Builder serverTransferData = ServerTransferData.ServerTransferDataProtoc.newBuilder(); + if (code != null) { + serverTransferData.setCode(code.toString()); + } + if (data != null) { + serverTransferData.setData(data); + } + return channel.writeAndFlush(serverTransferData); + } + } + +} diff --git a/landlords-common/src/main/java/org/nico/ratel/landlords/entity/ClientSide.java b/landlords-common/src/main/java/org/nico/ratel/landlords/entity/ClientSide.java new file mode 100644 index 0000000..e587d02 --- /dev/null +++ b/landlords-common/src/main/java/org/nico/ratel/landlords/entity/ClientSide.java @@ -0,0 +1,186 @@ +package org.nico.ratel.landlords.entity; + +import java.util.List; + +import org.nico.ratel.landlords.enums.ClientRole; +import org.nico.ratel.landlords.enums.ClientStatus; +import org.nico.ratel.landlords.enums.ClientType; + +import io.netty.channel.Channel; + +public class ClientSide { + + private int id; + + private int roomId; + + private int score; + + private int scoreInc; + + private String nickname; + + private List pokers; + + private ClientStatus status; + + private ClientRole role; + + private ClientType type; + + private ClientSide next; + + private ClientSide pre; + + private transient Channel channel; + + private String version; + + public ClientSide() {} + + public ClientSide(int id, ClientStatus status, Channel channel) { + this.id = id; + this.status = status; + this.channel = channel; + } + + public void init() { + roomId = 0; + pokers = null; + status = ClientStatus.TO_CHOOSE; + type = null; + next = null; + pre = null; + score = 0; + } + + public final ClientRole getRole() { + return role; + } + + public final void setRole(ClientRole role) { + this.role = role; + } + + public final String getNickname() { + return nickname; + } + + public final void setNickname(String nickname) { + this.nickname = nickname; + } + + public final Channel getChannel() { + return channel; + } + + public final void setChannel(Channel channel) { + this.channel = channel; + } + + public final int getRoomId() { + return roomId; + } + + public final void setRoomId(int roomId) { + this.roomId = roomId; + } + + public final List getPokers() { + return pokers; + } + + public final void setPokers(List pokers) { + this.pokers = pokers; + } + + public final int getScore() { + return score; + } + + public final void setScore(int score) { + this.score = score; + } + + public final void addScore(int score) { + this.score += score; + this.scoreInc = score; + } + + public final void setScoreInc(int scoreInc) { + this.scoreInc = scoreInc; + } + + public final int getScoreInc() { + return this.scoreInc; + } + + public final ClientStatus getStatus() { + return status; + } + + public final void setStatus(ClientStatus status) { + this.status = status; + } + + public final ClientType getType() { + return type; + } + + public final void setType(ClientType type) { + this.type = type; + } + + public final int getId() { + return id; + } + + public final void setId(int id) { + this.id = id; + } + + public final ClientSide getNext() { + return next; + } + + public final void setNext(ClientSide next) { + this.next = next; + } + + public final ClientSide getPre() { + return pre; + } + + public final void setPre(ClientSide pre) { + this.pre = pre; + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + id; + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + ClientSide other = (ClientSide) obj; + return id == other.id; + } + +} diff --git a/landlords-common/src/main/java/org/nico/ratel/landlords/entity/ClientTransferData.java b/landlords-common/src/main/java/org/nico/ratel/landlords/entity/ClientTransferData.java new file mode 100644 index 0000000..70d1d7c --- /dev/null +++ b/landlords-common/src/main/java/org/nico/ratel/landlords/entity/ClientTransferData.java @@ -0,0 +1,882 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: ClientTransferDataProtoc.proto + +package org.nico.ratel.landlords.entity; + +public final class ClientTransferData { + private ClientTransferData() {} + public static void registerAllExtensions( + com.google.protobuf.ExtensionRegistryLite registry) { + } + + public static void registerAllExtensions( + com.google.protobuf.ExtensionRegistry registry) { + registerAllExtensions( + (com.google.protobuf.ExtensionRegistryLite) registry); + } + public interface ClientTransferDataProtocOrBuilder extends + // @@protoc_insertion_point(interface_extends:org.nico.ratel.landlords.entity.ClientTransferDataProtoc) + com.google.protobuf.MessageOrBuilder { + + /** + * string code = 1; + */ + java.lang.String getCode(); + /** + * string code = 1; + */ + com.google.protobuf.ByteString + getCodeBytes(); + + /** + * string data = 2; + */ + java.lang.String getData(); + /** + * string data = 2; + */ + com.google.protobuf.ByteString + getDataBytes(); + + /** + * string info = 3; + */ + java.lang.String getInfo(); + /** + * string info = 3; + */ + com.google.protobuf.ByteString + getInfoBytes(); + } + /** + * Protobuf type {@code org.nico.ratel.landlords.entity.ClientTransferDataProtoc} + */ + public static final class ClientTransferDataProtoc extends + com.google.protobuf.GeneratedMessageV3 implements + // @@protoc_insertion_point(message_implements:org.nico.ratel.landlords.entity.ClientTransferDataProtoc) + ClientTransferDataProtocOrBuilder { + private static final long serialVersionUID = 0L; + // Use ClientTransferDataProtoc.newBuilder() to construct. + private ClientTransferDataProtoc(com.google.protobuf.GeneratedMessageV3.Builder builder) { + super(builder); + } + private ClientTransferDataProtoc() { + code_ = ""; + data_ = ""; + info_ = ""; + } + + @java.lang.Override + public final com.google.protobuf.UnknownFieldSet + getUnknownFields() { + return this.unknownFields; + } + private ClientTransferDataProtoc( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + this(); + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + int mutable_bitField0_ = 0; + com.google.protobuf.UnknownFieldSet.Builder unknownFields = + com.google.protobuf.UnknownFieldSet.newBuilder(); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + java.lang.String s = input.readStringRequireUtf8(); + + code_ = s; + break; + } + case 18: { + java.lang.String s = input.readStringRequireUtf8(); + + data_ = s; + break; + } + case 26: { + java.lang.String s = input.readStringRequireUtf8(); + + info_ = s; + break; + } + default: { + if (!parseUnknownFieldProto3( + input, unknownFields, extensionRegistry, tag)) { + done = true; + } + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e).setUnfinishedMessage(this); + } finally { + this.unknownFields = unknownFields.build(); + makeExtensionsImmutable(); + } + } + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.nico.ratel.landlords.entity.ClientTransferData.internal_static_org_nico_ratel_landlords_entity_ClientTransferDataProtoc_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.nico.ratel.landlords.entity.ClientTransferData.internal_static_org_nico_ratel_landlords_entity_ClientTransferDataProtoc_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.nico.ratel.landlords.entity.ClientTransferData.ClientTransferDataProtoc.class, org.nico.ratel.landlords.entity.ClientTransferData.ClientTransferDataProtoc.Builder.class); + } + + public static final int CODE_FIELD_NUMBER = 1; + private volatile java.lang.Object code_; + /** + * string code = 1; + */ + public java.lang.String getCode() { + java.lang.Object ref = code_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + code_ = s; + return s; + } + } + /** + * string code = 1; + */ + public com.google.protobuf.ByteString + getCodeBytes() { + java.lang.Object ref = code_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + code_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int DATA_FIELD_NUMBER = 2; + private volatile java.lang.Object data_; + /** + * string data = 2; + */ + public java.lang.String getData() { + java.lang.Object ref = data_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + data_ = s; + return s; + } + } + /** + * string data = 2; + */ + public com.google.protobuf.ByteString + getDataBytes() { + java.lang.Object ref = data_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + data_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int INFO_FIELD_NUMBER = 3; + private volatile java.lang.Object info_; + /** + * string info = 3; + */ + public java.lang.String getInfo() { + java.lang.Object ref = info_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + info_ = s; + return s; + } + } + /** + * string info = 3; + */ + public com.google.protobuf.ByteString + getInfoBytes() { + java.lang.Object ref = info_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + info_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + private byte memoizedIsInitialized = -1; + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (!getCodeBytes().isEmpty()) { + com.google.protobuf.GeneratedMessageV3.writeString(output, 1, code_); + } + if (!getDataBytes().isEmpty()) { + com.google.protobuf.GeneratedMessageV3.writeString(output, 2, data_); + } + if (!getInfoBytes().isEmpty()) { + com.google.protobuf.GeneratedMessageV3.writeString(output, 3, info_); + } + unknownFields.writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (!getCodeBytes().isEmpty()) { + size += com.google.protobuf.GeneratedMessageV3.computeStringSize(1, code_); + } + if (!getDataBytes().isEmpty()) { + size += com.google.protobuf.GeneratedMessageV3.computeStringSize(2, data_); + } + if (!getInfoBytes().isEmpty()) { + size += com.google.protobuf.GeneratedMessageV3.computeStringSize(3, info_); + } + size += unknownFields.getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.nico.ratel.landlords.entity.ClientTransferData.ClientTransferDataProtoc)) { + return super.equals(obj); + } + org.nico.ratel.landlords.entity.ClientTransferData.ClientTransferDataProtoc other = (org.nico.ratel.landlords.entity.ClientTransferData.ClientTransferDataProtoc) obj; + + boolean result = true; + result = result && getCode() + .equals(other.getCode()); + result = result && getData() + .equals(other.getData()); + result = result && getInfo() + .equals(other.getInfo()); + result = result && unknownFields.equals(other.unknownFields); + return result; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + CODE_FIELD_NUMBER; + hash = (53 * hash) + getCode().hashCode(); + hash = (37 * hash) + DATA_FIELD_NUMBER; + hash = (53 * hash) + getData().hashCode(); + hash = (37 * hash) + INFO_FIELD_NUMBER; + hash = (53 * hash) + getInfo().hashCode(); + hash = (29 * hash) + unknownFields.hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.nico.ratel.landlords.entity.ClientTransferData.ClientTransferDataProtoc parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.nico.ratel.landlords.entity.ClientTransferData.ClientTransferDataProtoc parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.nico.ratel.landlords.entity.ClientTransferData.ClientTransferDataProtoc parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.nico.ratel.landlords.entity.ClientTransferData.ClientTransferDataProtoc parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.nico.ratel.landlords.entity.ClientTransferData.ClientTransferDataProtoc parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + public static org.nico.ratel.landlords.entity.ClientTransferData.ClientTransferDataProtoc parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + public static org.nico.ratel.landlords.entity.ClientTransferData.ClientTransferDataProtoc parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + public static org.nico.ratel.landlords.entity.ClientTransferData.ClientTransferDataProtoc parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + public static org.nico.ratel.landlords.entity.ClientTransferData.ClientTransferDataProtoc parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input); + } + public static org.nico.ratel.landlords.entity.ClientTransferData.ClientTransferDataProtoc parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + public static org.nico.ratel.landlords.entity.ClientTransferData.ClientTransferDataProtoc parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + public static org.nico.ratel.landlords.entity.ClientTransferData.ClientTransferDataProtoc parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { return newBuilder(); } + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + public static Builder newBuilder(org.nico.ratel.landlords.entity.ClientTransferData.ClientTransferDataProtoc prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + /** + * Protobuf type {@code org.nico.ratel.landlords.entity.ClientTransferDataProtoc} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageV3.Builder implements + // @@protoc_insertion_point(builder_implements:org.nico.ratel.landlords.entity.ClientTransferDataProtoc) + org.nico.ratel.landlords.entity.ClientTransferData.ClientTransferDataProtocOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.nico.ratel.landlords.entity.ClientTransferData.internal_static_org_nico_ratel_landlords_entity_ClientTransferDataProtoc_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.nico.ratel.landlords.entity.ClientTransferData.internal_static_org_nico_ratel_landlords_entity_ClientTransferDataProtoc_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.nico.ratel.landlords.entity.ClientTransferData.ClientTransferDataProtoc.class, org.nico.ratel.landlords.entity.ClientTransferData.ClientTransferDataProtoc.Builder.class); + } + + // Construct using org.nico.ratel.landlords.entity.ClientTransferData.ClientTransferDataProtoc.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder( + com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessageV3 + .alwaysUseFieldBuilders) { + } + } + @java.lang.Override + public Builder clear() { + super.clear(); + code_ = ""; + + data_ = ""; + + info_ = ""; + + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return org.nico.ratel.landlords.entity.ClientTransferData.internal_static_org_nico_ratel_landlords_entity_ClientTransferDataProtoc_descriptor; + } + + @java.lang.Override + public org.nico.ratel.landlords.entity.ClientTransferData.ClientTransferDataProtoc getDefaultInstanceForType() { + return org.nico.ratel.landlords.entity.ClientTransferData.ClientTransferDataProtoc.getDefaultInstance(); + } + + @java.lang.Override + public org.nico.ratel.landlords.entity.ClientTransferData.ClientTransferDataProtoc build() { + org.nico.ratel.landlords.entity.ClientTransferData.ClientTransferDataProtoc result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.nico.ratel.landlords.entity.ClientTransferData.ClientTransferDataProtoc buildPartial() { + org.nico.ratel.landlords.entity.ClientTransferData.ClientTransferDataProtoc result = new org.nico.ratel.landlords.entity.ClientTransferData.ClientTransferDataProtoc(this); + result.code_ = code_; + result.data_ = data_; + result.info_ = info_; + onBuilt(); + return result; + } + + @java.lang.Override + public Builder clone() { + return (Builder) super.clone(); + } + @java.lang.Override + public Builder setField( + com.google.protobuf.Descriptors.FieldDescriptor field, + java.lang.Object value) { + return (Builder) super.setField(field, value); + } + @java.lang.Override + public Builder clearField( + com.google.protobuf.Descriptors.FieldDescriptor field) { + return (Builder) super.clearField(field); + } + @java.lang.Override + public Builder clearOneof( + com.google.protobuf.Descriptors.OneofDescriptor oneof) { + return (Builder) super.clearOneof(oneof); + } + @java.lang.Override + public Builder setRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, + int index, java.lang.Object value) { + return (Builder) super.setRepeatedField(field, index, value); + } + @java.lang.Override + public Builder addRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, + java.lang.Object value) { + return (Builder) super.addRepeatedField(field, value); + } + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.nico.ratel.landlords.entity.ClientTransferData.ClientTransferDataProtoc) { + return mergeFrom((org.nico.ratel.landlords.entity.ClientTransferData.ClientTransferDataProtoc)other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.nico.ratel.landlords.entity.ClientTransferData.ClientTransferDataProtoc other) { + if (other == org.nico.ratel.landlords.entity.ClientTransferData.ClientTransferDataProtoc.getDefaultInstance()) return this; + if (!other.getCode().isEmpty()) { + code_ = other.code_; + onChanged(); + } + if (!other.getData().isEmpty()) { + data_ = other.data_; + onChanged(); + } + if (!other.getInfo().isEmpty()) { + info_ = other.info_; + onChanged(); + } + this.mergeUnknownFields(other.unknownFields); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + org.nico.ratel.landlords.entity.ClientTransferData.ClientTransferDataProtoc parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (org.nico.ratel.landlords.entity.ClientTransferData.ClientTransferDataProtoc) e.getUnfinishedMessage(); + throw e.unwrapIOException(); + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + + private java.lang.Object code_ = ""; + /** + * string code = 1; + */ + public java.lang.String getCode() { + java.lang.Object ref = code_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + code_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * string code = 1; + */ + public com.google.protobuf.ByteString + getCodeBytes() { + java.lang.Object ref = code_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + code_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * string code = 1; + */ + public Builder setCode( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + + code_ = value; + onChanged(); + return this; + } + /** + * string code = 1; + */ + public Builder clearCode() { + + code_ = getDefaultInstance().getCode(); + onChanged(); + return this; + } + /** + * string code = 1; + */ + public Builder setCodeBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + checkByteStringIsUtf8(value); + + code_ = value; + onChanged(); + return this; + } + + private java.lang.Object data_ = ""; + /** + * string data = 2; + */ + public java.lang.String getData() { + java.lang.Object ref = data_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + data_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * string data = 2; + */ + public com.google.protobuf.ByteString + getDataBytes() { + java.lang.Object ref = data_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + data_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * string data = 2; + */ + public Builder setData( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + + data_ = value; + onChanged(); + return this; + } + /** + * string data = 2; + */ + public Builder clearData() { + + data_ = getDefaultInstance().getData(); + onChanged(); + return this; + } + /** + * string data = 2; + */ + public Builder setDataBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + checkByteStringIsUtf8(value); + + data_ = value; + onChanged(); + return this; + } + + private java.lang.Object info_ = ""; + /** + * string info = 3; + */ + public java.lang.String getInfo() { + java.lang.Object ref = info_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + info_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + /** + * string info = 3; + */ + public com.google.protobuf.ByteString + getInfoBytes() { + java.lang.Object ref = info_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + info_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + /** + * string info = 3; + */ + public Builder setInfo( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + + info_ = value; + onChanged(); + return this; + } + /** + * string info = 3; + */ + public Builder clearInfo() { + + info_ = getDefaultInstance().getInfo(); + onChanged(); + return this; + } + /** + * string info = 3; + */ + public Builder setInfoBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + checkByteStringIsUtf8(value); + + info_ = value; + onChanged(); + return this; + } + @java.lang.Override + public final Builder setUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return super.setUnknownFieldsProto3(unknownFields); + } + + @java.lang.Override + public final Builder mergeUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return super.mergeUnknownFields(unknownFields); + } + + + // @@protoc_insertion_point(builder_scope:org.nico.ratel.landlords.entity.ClientTransferDataProtoc) + } + + // @@protoc_insertion_point(class_scope:org.nico.ratel.landlords.entity.ClientTransferDataProtoc) + private static final org.nico.ratel.landlords.entity.ClientTransferData.ClientTransferDataProtoc DEFAULT_INSTANCE; + static { + DEFAULT_INSTANCE = new org.nico.ratel.landlords.entity.ClientTransferData.ClientTransferDataProtoc(); + } + + public static org.nico.ratel.landlords.entity.ClientTransferData.ClientTransferDataProtoc getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public ClientTransferDataProtoc parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new ClientTransferDataProtoc(input, extensionRegistry); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.nico.ratel.landlords.entity.ClientTransferData.ClientTransferDataProtoc getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + + } + + private static final com.google.protobuf.Descriptors.Descriptor + internal_static_org_nico_ratel_landlords_entity_ClientTransferDataProtoc_descriptor; + private static final + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internal_static_org_nico_ratel_landlords_entity_ClientTransferDataProtoc_fieldAccessorTable; + + public static com.google.protobuf.Descriptors.FileDescriptor + getDescriptor() { + return descriptor; + } + private static com.google.protobuf.Descriptors.FileDescriptor + descriptor; + static { + java.lang.String[] descriptorData = { + "\n\036ClientTransferDataProtoc.proto\022\037org.ni" + + "co.ratel.landlords.entity\"D\n\030ClientTrans" + + "ferDataProtoc\022\014\n\004code\030\001 \001(\t\022\014\n\004data\030\002 \001(" + + "\t\022\014\n\004info\030\003 \001(\tB5\n\037org.nico.ratel.landlo" + + "rds.entityB\022ClientTransferDatab\006proto3" + }; + com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner = + new com.google.protobuf.Descriptors.FileDescriptor. InternalDescriptorAssigner() { + public com.google.protobuf.ExtensionRegistry assignDescriptors( + com.google.protobuf.Descriptors.FileDescriptor root) { + descriptor = root; + return null; + } + }; + com.google.protobuf.Descriptors.FileDescriptor + .internalBuildGeneratedFileFrom(descriptorData, + new com.google.protobuf.Descriptors.FileDescriptor[] { + }, assigner); + internal_static_org_nico_ratel_landlords_entity_ClientTransferDataProtoc_descriptor = + getDescriptor().getMessageTypes().get(0); + internal_static_org_nico_ratel_landlords_entity_ClientTransferDataProtoc_fieldAccessorTable = new + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( + internal_static_org_nico_ratel_landlords_entity_ClientTransferDataProtoc_descriptor, + new java.lang.String[] { "Code", "Data", "Info", }); + } + + // @@protoc_insertion_point(outer_class_scope) +} diff --git a/landlords-common/src/main/java/org/nico/ratel/landlords/entity/Msg.java b/landlords-common/src/main/java/org/nico/ratel/landlords/entity/Msg.java new file mode 100644 index 0000000..b0a59de --- /dev/null +++ b/landlords-common/src/main/java/org/nico/ratel/landlords/entity/Msg.java @@ -0,0 +1,34 @@ +package org.nico.ratel.landlords.entity; + +public class Msg { + + private String code; + + private String data; + + private String info; + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } + + public String getData() { + return data; + } + + public void setData(String data) { + this.data = data; + } + + public String getInfo() { + return info; + } + + public void setInfo(String info) { + this.info = info; + } +} diff --git a/landlords-common/src/main/java/org/nico/ratel/landlords/entity/Poker.java b/landlords-common/src/main/java/org/nico/ratel/landlords/entity/Poker.java new file mode 100644 index 0000000..2133bd6 --- /dev/null +++ b/landlords-common/src/main/java/org/nico/ratel/landlords/entity/Poker.java @@ -0,0 +1,70 @@ +package org.nico.ratel.landlords.entity; + +import org.nico.ratel.landlords.enums.PokerLevel; +import org.nico.ratel.landlords.enums.PokerType; + +/** + * Poke, with {@link PokerLevel} and {@link PokerType} + * + * @author nico + */ +public class Poker { + + private PokerLevel level; + + private PokerType type; + + public Poker() { + } + + public Poker(PokerLevel level, PokerType type) { + this.level = level; + this.type = type; + } + + public final PokerLevel getLevel() { + return level; + } + + public final void setLevel(PokerLevel level) { + this.level = level; + } + + public final PokerType getType() { + return type; + } + + public final void setType(PokerType type) { + this.type = type; + } + + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((level == null) ? 0 : level.hashCode()); + result = prime * result + ((type == null) ? 0 : type.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Poker other = (Poker) obj; + if (level != other.level) + return false; + return type == other.type; + } + + @Override + public String toString() { + return level.getLevel() + " "; + } + +} diff --git a/landlords-common/src/main/java/org/nico/ratel/landlords/entity/PokerSell.java b/landlords-common/src/main/java/org/nico/ratel/landlords/entity/PokerSell.java new file mode 100644 index 0000000..f3a8d60 --- /dev/null +++ b/landlords-common/src/main/java/org/nico/ratel/landlords/entity/PokerSell.java @@ -0,0 +1,62 @@ +package org.nico.ratel.landlords.entity; + +import org.nico.ratel.landlords.enums.SellType; +import org.nico.ratel.landlords.helper.PokerHelper; + +import java.util.List; + +public class PokerSell { + + private int score; + + private SellType sellType; + + private List sellPokers; + + private int coreLevel; + + public PokerSell(SellType sellType, List sellPokers, int coreLevel) { + this.score = PokerHelper.parseScore(sellType, coreLevel); + this.sellType = sellType; + this.sellPokers = sellPokers; + this.coreLevel = coreLevel; + } + + public final int getCoreLevel() { + return coreLevel; + } + + public final void setCoreLevel(int coreLevel) { + this.coreLevel = coreLevel; + } + + public final int getScore() { + return score; + } + + public final void setScore(int score) { + this.score = score; + } + + public final SellType getSellType() { + return sellType; + } + + public final void setSellType(SellType sellType) { + this.sellType = sellType; + } + + public final List getSellPokers() { + return sellPokers; + } + + public final void setSellPokers(List sellPokers) { + this.sellPokers = sellPokers; + } + + @Override + public String toString() { + return sellType + "\t| " + score + "\t|" + sellPokers; + } + +} diff --git a/landlords-common/src/main/java/org/nico/ratel/landlords/entity/Room.java b/landlords-common/src/main/java/org/nico/ratel/landlords/entity/Room.java new file mode 100644 index 0000000..4bb54c0 --- /dev/null +++ b/landlords-common/src/main/java/org/nico/ratel/landlords/entity/Room.java @@ -0,0 +1,215 @@ +package org.nico.ratel.landlords.entity; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentSkipListMap; +import java.util.concurrent.locks.ReentrantLock; + +import org.nico.noson.annotations.JsonIgnore; +import org.nico.ratel.landlords.enums.RoomStatus; +import org.nico.ratel.landlords.enums.RoomType; + +public class Room { + + private int id; + + private String roomOwner; + + private RoomStatus status; + + private RoomType type; + + private Map clientSideMap; + + private LinkedList clientSideList; + + private int landlordId = -1; + + private List landlordPokers; + + private PokerSell lastPokerShell; + + private int lastSellClient = -1; + + private int currentSellClient = -1; + + private int difficultyCoefficient; + + private long lastFlushTime; + + private long createTime; + + private int firstSellClient; + + /** 观战者列表 */ + private List watcherList = new ArrayList<>(5); + + private int scoreRate = 1; + + private int baseScore = 3; + + public Room() { + } + + public Room(int id) { + this.id = id; + this.clientSideMap = new ConcurrentSkipListMap<>(); + this.clientSideList = new LinkedList<>(); + this.status = RoomStatus.WAIT; + this.createTime = System.currentTimeMillis(); + } + + public int getScore() { + return this.baseScore * this.scoreRate; + } + + public int getBaseScore() { + return this.baseScore; + } + + public void setBaseScore(int baseScore) { + this.baseScore = baseScore; + } + + public int getScoreRate() { + return this.scoreRate; + } + + public void setScoreRate(int scoreRate) { + this.scoreRate = scoreRate; + } + + public void initScoreRate() { + this.scoreRate = 1; + } + + public void increaseRate() { + this.scoreRate *= 2; + } + + public final long getCreateTime() { + return createTime; + } + + public final void setCreateTime(long createTime) { + this.createTime = createTime; + } + + public final int getDifficultyCoefficient() { + return difficultyCoefficient; + } + + public final void setDifficultyCoefficient(int difficultyCoefficient) { + this.difficultyCoefficient = difficultyCoefficient; + } + + public final RoomType getType() { + return type; + } + + public final void setType(RoomType type) { + this.type = type; + } + + public final PokerSell getLastPokerShell() { + return lastPokerShell; + } + + public final void setLastPokerShell(PokerSell lastPokerShell) { + this.lastPokerShell = lastPokerShell; + } + + public final int getCurrentSellClient() { + return currentSellClient; + } + + public final void setCurrentSellClient(int currentSellClient) { + this.currentSellClient = currentSellClient; + } + + public long getLastFlushTime() { + return lastFlushTime; + } + + public void setLastFlushTime(long lastFlushTime) { + this.lastFlushTime = lastFlushTime; + } + + public int getLastSellClient() { + return lastSellClient; + } + + public void setLastSellClient(int lastSellClient) { + this.lastSellClient = lastSellClient; + } + + public int getLandlordId() { + return landlordId; + } + + public void setLandlordId(int landlordId) { + this.landlordId = landlordId; + } + + public LinkedList getClientSideList() { + return clientSideList; + } + + public void setClientSideList(LinkedList clientSideList) { + this.clientSideList = clientSideList; + } + + public List getLandlordPokers() { + return landlordPokers; + } + + public void setLandlordPokers(List landlordPokers) { + this.landlordPokers = landlordPokers; + } + + public final String getRoomOwner() { + return roomOwner; + } + + public final void setRoomOwner(String roomOwner) { + this.roomOwner = roomOwner; + } + + public final int getId() { + return id; + } + + public final void setId(int id) { + this.id = id; + } + + public final RoomStatus getStatus() { + return status; + } + + public final void setStatus(RoomStatus status) { + this.status = status; + } + + public final Map getClientSideMap() { + return clientSideMap; + } + + public final void setClientSideMap(Map clientSideMap) { + this.clientSideMap = clientSideMap; + } + + public int getFirstSellClient() { + return firstSellClient; + } + + public void setFirstSellClient(int firstSellClient) { + this.firstSellClient = firstSellClient; + } + + public List getWatcherList() { + return watcherList; + } +} diff --git a/landlords-common/src/main/java/org/nico/ratel/landlords/entity/ServerTransferData.java b/landlords-common/src/main/java/org/nico/ratel/landlords/entity/ServerTransferData.java new file mode 100644 index 0000000..45ccce3 --- /dev/null +++ b/landlords-common/src/main/java/org/nico/ratel/landlords/entity/ServerTransferData.java @@ -0,0 +1,945 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: ServerTransferDataProtoc.proto + +package org.nico.ratel.landlords.entity; + +public final class ServerTransferData { + private ServerTransferData() { + } + + public static void registerAllExtensions( + com.google.protobuf.ExtensionRegistryLite registry) { + } + + public static void registerAllExtensions( + com.google.protobuf.ExtensionRegistry registry) { + registerAllExtensions( + (com.google.protobuf.ExtensionRegistryLite) registry); + } + + public interface ServerTransferDataProtocOrBuilder extends + // @@protoc_insertion_point(interface_extends:org.nico.ratel.landlords.entity.ServerTransferDataProtoc) + com.google.protobuf.MessageOrBuilder { + + /** + * string code = 1; + */ + java.lang.String getCode(); + + /** + * string code = 1; + */ + com.google.protobuf.ByteString + getCodeBytes(); + + /** + * string data = 2; + */ + java.lang.String getData(); + + /** + * string data = 2; + */ + com.google.protobuf.ByteString + getDataBytes(); + + /** + * string info = 3; + */ + java.lang.String getInfo(); + + /** + * string info = 3; + */ + com.google.protobuf.ByteString + getInfoBytes(); + } + + /** + * Protobuf type {@code org.nico.ratel.landlords.entity.ServerTransferDataProtoc} + */ + public static final class ServerTransferDataProtoc extends + com.google.protobuf.GeneratedMessageV3 implements + // @@protoc_insertion_point(message_implements:org.nico.ratel.landlords.entity.ServerTransferDataProtoc) + ServerTransferDataProtocOrBuilder { + private static final long serialVersionUID = 0L; + + // Use ServerTransferDataProtoc.newBuilder() to construct. + private ServerTransferDataProtoc(com.google.protobuf.GeneratedMessageV3.Builder builder) { + super(builder); + } + + private ServerTransferDataProtoc() { + code_ = ""; + data_ = ""; + info_ = ""; + } + + @java.lang.Override + public final com.google.protobuf.UnknownFieldSet + getUnknownFields() { + return this.unknownFields; + } + + private ServerTransferDataProtoc( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + this(); + if (extensionRegistry == null) { + throw new java.lang.NullPointerException(); + } + int mutable_bitField0_ = 0; + com.google.protobuf.UnknownFieldSet.Builder unknownFields = + com.google.protobuf.UnknownFieldSet.newBuilder(); + try { + boolean done = false; + while (!done) { + int tag = input.readTag(); + switch (tag) { + case 0: + done = true; + break; + case 10: { + java.lang.String s = input.readStringRequireUtf8(); + + code_ = s; + break; + } + case 18: { + java.lang.String s = input.readStringRequireUtf8(); + + data_ = s; + break; + } + case 26: { + java.lang.String s = input.readStringRequireUtf8(); + + info_ = s; + break; + } + default: { + if (!parseUnknownFieldProto3( + input, unknownFields, extensionRegistry, tag)) { + done = true; + } + break; + } + } + } + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(this); + } catch (java.io.IOException e) { + throw new com.google.protobuf.InvalidProtocolBufferException( + e).setUnfinishedMessage(this); + } finally { + this.unknownFields = unknownFields.build(); + makeExtensionsImmutable(); + } + } + + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.nico.ratel.landlords.entity.ServerTransferData.internal_static_org_nico_ratel_landlords_entity_ServerTransferDataProtoc_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.nico.ratel.landlords.entity.ServerTransferData.internal_static_org_nico_ratel_landlords_entity_ServerTransferDataProtoc_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.nico.ratel.landlords.entity.ServerTransferData.ServerTransferDataProtoc.class, org.nico.ratel.landlords.entity.ServerTransferData.ServerTransferDataProtoc.Builder.class); + } + + public static final int CODE_FIELD_NUMBER = 1; + private volatile java.lang.Object code_; + + /** + * string code = 1; + */ + public java.lang.String getCode() { + java.lang.Object ref = code_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + code_ = s; + return s; + } + } + + /** + * string code = 1; + */ + public com.google.protobuf.ByteString + getCodeBytes() { + java.lang.Object ref = code_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + code_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int DATA_FIELD_NUMBER = 2; + private volatile java.lang.Object data_; + + /** + * string data = 2; + */ + public java.lang.String getData() { + java.lang.Object ref = data_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + data_ = s; + return s; + } + } + + /** + * string data = 2; + */ + public com.google.protobuf.ByteString + getDataBytes() { + java.lang.Object ref = data_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + data_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + public static final int INFO_FIELD_NUMBER = 3; + private volatile java.lang.Object info_; + + /** + * string info = 3; + */ + public java.lang.String getInfo() { + java.lang.Object ref = info_; + if (ref instanceof java.lang.String) { + return (java.lang.String) ref; + } else { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + info_ = s; + return s; + } + } + + /** + * string info = 3; + */ + public com.google.protobuf.ByteString + getInfoBytes() { + java.lang.Object ref = info_; + if (ref instanceof java.lang.String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + info_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + private byte memoizedIsInitialized = -1; + + @java.lang.Override + public final boolean isInitialized() { + byte isInitialized = memoizedIsInitialized; + if (isInitialized == 1) return true; + if (isInitialized == 0) return false; + + memoizedIsInitialized = 1; + return true; + } + + @java.lang.Override + public void writeTo(com.google.protobuf.CodedOutputStream output) + throws java.io.IOException { + if (!getCodeBytes().isEmpty()) { + com.google.protobuf.GeneratedMessageV3.writeString(output, 1, code_); + } + if (!getDataBytes().isEmpty()) { + com.google.protobuf.GeneratedMessageV3.writeString(output, 2, data_); + } + if (!getInfoBytes().isEmpty()) { + com.google.protobuf.GeneratedMessageV3.writeString(output, 3, info_); + } + unknownFields.writeTo(output); + } + + @java.lang.Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) return size; + + size = 0; + if (!getCodeBytes().isEmpty()) { + size += com.google.protobuf.GeneratedMessageV3.computeStringSize(1, code_); + } + if (!getDataBytes().isEmpty()) { + size += com.google.protobuf.GeneratedMessageV3.computeStringSize(2, data_); + } + if (!getInfoBytes().isEmpty()) { + size += com.google.protobuf.GeneratedMessageV3.computeStringSize(3, info_); + } + size += unknownFields.getSerializedSize(); + memoizedSize = size; + return size; + } + + @java.lang.Override + public boolean equals(final java.lang.Object obj) { + if (obj == this) { + return true; + } + if (!(obj instanceof org.nico.ratel.landlords.entity.ServerTransferData.ServerTransferDataProtoc)) { + return super.equals(obj); + } + org.nico.ratel.landlords.entity.ServerTransferData.ServerTransferDataProtoc other = (org.nico.ratel.landlords.entity.ServerTransferData.ServerTransferDataProtoc) obj; + + boolean result = true; + result = result && getCode() + .equals(other.getCode()); + result = result && getData() + .equals(other.getData()); + result = result && getInfo() + .equals(other.getInfo()); + result = result && unknownFields.equals(other.unknownFields); + return result; + } + + @java.lang.Override + public int hashCode() { + if (memoizedHashCode != 0) { + return memoizedHashCode; + } + int hash = 41; + hash = (19 * hash) + getDescriptor().hashCode(); + hash = (37 * hash) + CODE_FIELD_NUMBER; + hash = (53 * hash) + getCode().hashCode(); + hash = (37 * hash) + DATA_FIELD_NUMBER; + hash = (53 * hash) + getData().hashCode(); + hash = (37 * hash) + INFO_FIELD_NUMBER; + hash = (53 * hash) + getInfo().hashCode(); + hash = (29 * hash) + unknownFields.hashCode(); + memoizedHashCode = hash; + return hash; + } + + public static org.nico.ratel.landlords.entity.ServerTransferData.ServerTransferDataProtoc parseFrom( + java.nio.ByteBuffer data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + + public static org.nico.ratel.landlords.entity.ServerTransferData.ServerTransferDataProtoc parseFrom( + java.nio.ByteBuffer data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + + public static org.nico.ratel.landlords.entity.ServerTransferData.ServerTransferDataProtoc parseFrom( + com.google.protobuf.ByteString data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + + public static org.nico.ratel.landlords.entity.ServerTransferData.ServerTransferDataProtoc parseFrom( + com.google.protobuf.ByteString data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + + public static org.nico.ratel.landlords.entity.ServerTransferData.ServerTransferDataProtoc parseFrom(byte[] data) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data); + } + + public static org.nico.ratel.landlords.entity.ServerTransferData.ServerTransferDataProtoc parseFrom( + byte[] data, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return PARSER.parseFrom(data, extensionRegistry); + } + + public static org.nico.ratel.landlords.entity.ServerTransferData.ServerTransferDataProtoc parseFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + + public static org.nico.ratel.landlords.entity.ServerTransferData.ServerTransferDataProtoc parseFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + + public static org.nico.ratel.landlords.entity.ServerTransferData.ServerTransferDataProtoc parseDelimitedFrom(java.io.InputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input); + } + + public static org.nico.ratel.landlords.entity.ServerTransferData.ServerTransferDataProtoc parseDelimitedFrom( + java.io.InputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseDelimitedWithIOException(PARSER, input, extensionRegistry); + } + + public static org.nico.ratel.landlords.entity.ServerTransferData.ServerTransferDataProtoc parseFrom( + com.google.protobuf.CodedInputStream input) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input); + } + + public static org.nico.ratel.landlords.entity.ServerTransferData.ServerTransferDataProtoc parseFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + return com.google.protobuf.GeneratedMessageV3 + .parseWithIOException(PARSER, input, extensionRegistry); + } + + @java.lang.Override + public Builder newBuilderForType() { + return newBuilder(); + } + + public static Builder newBuilder() { + return DEFAULT_INSTANCE.toBuilder(); + } + + public static Builder newBuilder(org.nico.ratel.landlords.entity.ServerTransferData.ServerTransferDataProtoc prototype) { + return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype); + } + + @java.lang.Override + public Builder toBuilder() { + return this == DEFAULT_INSTANCE + ? new Builder() : new Builder().mergeFrom(this); + } + + @java.lang.Override + protected Builder newBuilderForType( + com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { + Builder builder = new Builder(parent); + return builder; + } + + /** + * Protobuf type {@code org.nico.ratel.landlords.entity.ServerTransferDataProtoc} + */ + public static final class Builder extends + com.google.protobuf.GeneratedMessageV3.Builder implements + // @@protoc_insertion_point(builder_implements:org.nico.ratel.landlords.entity.ServerTransferDataProtoc) + org.nico.ratel.landlords.entity.ServerTransferData.ServerTransferDataProtocOrBuilder { + public static final com.google.protobuf.Descriptors.Descriptor + getDescriptor() { + return org.nico.ratel.landlords.entity.ServerTransferData.internal_static_org_nico_ratel_landlords_entity_ServerTransferDataProtoc_descriptor; + } + + @java.lang.Override + protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internalGetFieldAccessorTable() { + return org.nico.ratel.landlords.entity.ServerTransferData.internal_static_org_nico_ratel_landlords_entity_ServerTransferDataProtoc_fieldAccessorTable + .ensureFieldAccessorsInitialized( + org.nico.ratel.landlords.entity.ServerTransferData.ServerTransferDataProtoc.class, org.nico.ratel.landlords.entity.ServerTransferData.ServerTransferDataProtoc.Builder.class); + } + + // Construct using org.nico.ratel.landlords.entity.ServerTransferData.ServerTransferDataProtoc.newBuilder() + private Builder() { + maybeForceBuilderInitialization(); + } + + private Builder( + com.google.protobuf.GeneratedMessageV3.BuilderParent parent) { + super(parent); + maybeForceBuilderInitialization(); + } + + private void maybeForceBuilderInitialization() { + if (com.google.protobuf.GeneratedMessageV3 + .alwaysUseFieldBuilders) { + } + } + + @java.lang.Override + public Builder clear() { + super.clear(); + code_ = ""; + + data_ = ""; + + info_ = ""; + + return this; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.Descriptor + getDescriptorForType() { + return org.nico.ratel.landlords.entity.ServerTransferData.internal_static_org_nico_ratel_landlords_entity_ServerTransferDataProtoc_descriptor; + } + + @java.lang.Override + public org.nico.ratel.landlords.entity.ServerTransferData.ServerTransferDataProtoc getDefaultInstanceForType() { + return org.nico.ratel.landlords.entity.ServerTransferData.ServerTransferDataProtoc.getDefaultInstance(); + } + + @java.lang.Override + public org.nico.ratel.landlords.entity.ServerTransferData.ServerTransferDataProtoc build() { + org.nico.ratel.landlords.entity.ServerTransferData.ServerTransferDataProtoc result = buildPartial(); + if (!result.isInitialized()) { + throw newUninitializedMessageException(result); + } + return result; + } + + @java.lang.Override + public org.nico.ratel.landlords.entity.ServerTransferData.ServerTransferDataProtoc buildPartial() { + org.nico.ratel.landlords.entity.ServerTransferData.ServerTransferDataProtoc result = new org.nico.ratel.landlords.entity.ServerTransferData.ServerTransferDataProtoc(this); + result.code_ = code_; + result.data_ = data_; + result.info_ = info_; + onBuilt(); + return result; + } + + @java.lang.Override + public Builder clone() { + return (Builder) super.clone(); + } + + @java.lang.Override + public Builder setField( + com.google.protobuf.Descriptors.FieldDescriptor field, + java.lang.Object value) { + return (Builder) super.setField(field, value); + } + + @java.lang.Override + public Builder clearField( + com.google.protobuf.Descriptors.FieldDescriptor field) { + return (Builder) super.clearField(field); + } + + @java.lang.Override + public Builder clearOneof( + com.google.protobuf.Descriptors.OneofDescriptor oneof) { + return (Builder) super.clearOneof(oneof); + } + + @java.lang.Override + public Builder setRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, + int index, java.lang.Object value) { + return (Builder) super.setRepeatedField(field, index, value); + } + + @java.lang.Override + public Builder addRepeatedField( + com.google.protobuf.Descriptors.FieldDescriptor field, + java.lang.Object value) { + return (Builder) super.addRepeatedField(field, value); + } + + @java.lang.Override + public Builder mergeFrom(com.google.protobuf.Message other) { + if (other instanceof org.nico.ratel.landlords.entity.ServerTransferData.ServerTransferDataProtoc) { + return mergeFrom((org.nico.ratel.landlords.entity.ServerTransferData.ServerTransferDataProtoc) other); + } else { + super.mergeFrom(other); + return this; + } + } + + public Builder mergeFrom(org.nico.ratel.landlords.entity.ServerTransferData.ServerTransferDataProtoc other) { + if (other == org.nico.ratel.landlords.entity.ServerTransferData.ServerTransferDataProtoc.getDefaultInstance()) + return this; + if (!other.getCode().isEmpty()) { + code_ = other.code_; + onChanged(); + } + if (!other.getData().isEmpty()) { + data_ = other.data_; + onChanged(); + } + if (!other.getInfo().isEmpty()) { + info_ = other.info_; + onChanged(); + } + this.mergeUnknownFields(other.unknownFields); + onChanged(); + return this; + } + + @java.lang.Override + public final boolean isInitialized() { + return true; + } + + @java.lang.Override + public Builder mergeFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws java.io.IOException { + org.nico.ratel.landlords.entity.ServerTransferData.ServerTransferDataProtoc parsedMessage = null; + try { + parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry); + } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = (org.nico.ratel.landlords.entity.ServerTransferData.ServerTransferDataProtoc) e.getUnfinishedMessage(); + throw e.unwrapIOException(); + } finally { + if (parsedMessage != null) { + mergeFrom(parsedMessage); + } + } + return this; + } + + private java.lang.Object code_ = ""; + + /** + * string code = 1; + */ + public java.lang.String getCode() { + java.lang.Object ref = code_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + code_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + + /** + * string code = 1; + */ + public com.google.protobuf.ByteString + getCodeBytes() { + java.lang.Object ref = code_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + code_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + /** + * string code = 1; + */ + public Builder setCode( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + + code_ = value; + onChanged(); + return this; + } + + /** + * string code = 1; + */ + public Builder clearCode() { + + code_ = getDefaultInstance().getCode(); + onChanged(); + return this; + } + + /** + * string code = 1; + */ + public Builder setCodeBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + checkByteStringIsUtf8(value); + + code_ = value; + onChanged(); + return this; + } + + private java.lang.Object data_ = ""; + + /** + * string data = 2; + */ + public java.lang.String getData() { + java.lang.Object ref = data_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + data_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + + /** + * string data = 2; + */ + public com.google.protobuf.ByteString + getDataBytes() { + java.lang.Object ref = data_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + data_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + /** + * string data = 2; + */ + public Builder setData( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + + data_ = value; + onChanged(); + return this; + } + + /** + * string data = 2; + */ + public Builder clearData() { + + data_ = getDefaultInstance().getData(); + onChanged(); + return this; + } + + /** + * string data = 2; + */ + public Builder setDataBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + checkByteStringIsUtf8(value); + + data_ = value; + onChanged(); + return this; + } + + private java.lang.Object info_ = ""; + + /** + * string info = 3; + */ + public java.lang.String getInfo() { + java.lang.Object ref = info_; + if (!(ref instanceof java.lang.String)) { + com.google.protobuf.ByteString bs = + (com.google.protobuf.ByteString) ref; + java.lang.String s = bs.toStringUtf8(); + info_ = s; + return s; + } else { + return (java.lang.String) ref; + } + } + + /** + * string info = 3; + */ + public com.google.protobuf.ByteString + getInfoBytes() { + java.lang.Object ref = info_; + if (ref instanceof String) { + com.google.protobuf.ByteString b = + com.google.protobuf.ByteString.copyFromUtf8( + (java.lang.String) ref); + info_ = b; + return b; + } else { + return (com.google.protobuf.ByteString) ref; + } + } + + /** + * string info = 3; + */ + public Builder setInfo( + java.lang.String value) { + if (value == null) { + throw new NullPointerException(); + } + + info_ = value; + onChanged(); + return this; + } + + /** + * string info = 3; + */ + public Builder clearInfo() { + + info_ = getDefaultInstance().getInfo(); + onChanged(); + return this; + } + + /** + * string info = 3; + */ + public Builder setInfoBytes( + com.google.protobuf.ByteString value) { + if (value == null) { + throw new NullPointerException(); + } + checkByteStringIsUtf8(value); + + info_ = value; + onChanged(); + return this; + } + + @java.lang.Override + public final Builder setUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return super.setUnknownFieldsProto3(unknownFields); + } + + @java.lang.Override + public final Builder mergeUnknownFields( + final com.google.protobuf.UnknownFieldSet unknownFields) { + return super.mergeUnknownFields(unknownFields); + } + + + // @@protoc_insertion_point(builder_scope:org.nico.ratel.landlords.entity.ServerTransferDataProtoc) + } + + // @@protoc_insertion_point(class_scope:org.nico.ratel.landlords.entity.ServerTransferDataProtoc) + private static final org.nico.ratel.landlords.entity.ServerTransferData.ServerTransferDataProtoc DEFAULT_INSTANCE; + + static { + DEFAULT_INSTANCE = new org.nico.ratel.landlords.entity.ServerTransferData.ServerTransferDataProtoc(); + } + + public static org.nico.ratel.landlords.entity.ServerTransferData.ServerTransferDataProtoc getDefaultInstance() { + return DEFAULT_INSTANCE; + } + + private static final com.google.protobuf.Parser + PARSER = new com.google.protobuf.AbstractParser() { + @java.lang.Override + public ServerTransferDataProtoc parsePartialFrom( + com.google.protobuf.CodedInputStream input, + com.google.protobuf.ExtensionRegistryLite extensionRegistry) + throws com.google.protobuf.InvalidProtocolBufferException { + return new ServerTransferDataProtoc(input, extensionRegistry); + } + }; + + public static com.google.protobuf.Parser parser() { + return PARSER; + } + + @java.lang.Override + public com.google.protobuf.Parser getParserForType() { + return PARSER; + } + + @java.lang.Override + public org.nico.ratel.landlords.entity.ServerTransferData.ServerTransferDataProtoc getDefaultInstanceForType() { + return DEFAULT_INSTANCE; + } + + } + + private static final com.google.protobuf.Descriptors.Descriptor + internal_static_org_nico_ratel_landlords_entity_ServerTransferDataProtoc_descriptor; + private static final + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable + internal_static_org_nico_ratel_landlords_entity_ServerTransferDataProtoc_fieldAccessorTable; + + public static com.google.protobuf.Descriptors.FileDescriptor + getDescriptor() { + return descriptor; + } + + private static com.google.protobuf.Descriptors.FileDescriptor + descriptor; + + static { + java.lang.String[] descriptorData = { + "\n\036ServerTransferDataProtoc.proto\022\037org.ni" + + "co.ratel.landlords.entity\"D\n\030ServerTrans" + + "ferDataProtoc\022\014\n\004code\030\001 \001(\t\022\014\n\004data\030\002 \001(" + + "\t\022\014\n\004info\030\003 \001(\tB5\n\037org.nico.ratel.landlo" + + "rds.entityB\022ServerTransferDatab\006proto3" + }; + com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner = + new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() { + public com.google.protobuf.ExtensionRegistry assignDescriptors( + com.google.protobuf.Descriptors.FileDescriptor root) { + descriptor = root; + return null; + } + }; + com.google.protobuf.Descriptors.FileDescriptor + .internalBuildGeneratedFileFrom(descriptorData, + new com.google.protobuf.Descriptors.FileDescriptor[]{ + }, assigner); + internal_static_org_nico_ratel_landlords_entity_ServerTransferDataProtoc_descriptor = + getDescriptor().getMessageTypes().get(0); + internal_static_org_nico_ratel_landlords_entity_ServerTransferDataProtoc_fieldAccessorTable = new + com.google.protobuf.GeneratedMessageV3.FieldAccessorTable( + internal_static_org_nico_ratel_landlords_entity_ServerTransferDataProtoc_descriptor, + new java.lang.String[]{"Code", "Data", "Info",}); + } + + // @@protoc_insertion_point(outer_class_scope) +} diff --git a/landlords-common/src/main/java/org/nico/ratel/landlords/enums/ClientEventCode.java b/landlords-common/src/main/java/org/nico/ratel/landlords/enums/ClientEventCode.java new file mode 100644 index 0000000..972b4de --- /dev/null +++ b/landlords-common/src/main/java/org/nico/ratel/landlords/enums/ClientEventCode.java @@ -0,0 +1,85 @@ +package org.nico.ratel.landlords.enums; + +import java.io.Serializable; + +public enum ClientEventCode implements Serializable { + + CODE_CLIENT_NICKNAME_SET("设置昵称"), + + CODE_CLIENT_EXIT("客户端退出"), + + CODE_CLIENT_KICK("客户端被踢出"), + + CODE_CLIENT_CONNECT("客户端加入成功"), + + CODE_SHOW_OPTIONS("全局选项列表"), + + CODE_SHOW_OPTIONS_SETTING("设置选项"), + + CODE_SHOW_OPTIONS_PVP("玩家对战选项"), + + CODE_SHOW_OPTIONS_PVE("人机对战选项"), + + CODE_SHOW_ROOMS("展示房间列表"), + + CODE_SHOW_POKERS("展示Poker"), + + CODE_ROOM_CREATE_SUCCESS("创建房间成功"), + + CODE_ROOM_JOIN_SUCCESS("加入房间成功"), + + CODE_ROOM_JOIN_FAIL_BY_FULL("房间人数已满"), + + CODE_ROOM_JOIN_FAIL_BY_INEXIST("加入-房间不存在"), + + CODE_ROOM_PLAY_FAIL_BY_INEXIST1("出牌-房间不存在"), + + CODE_GAME_STARTING("开始游戏"), + + CODE_GAME_LANDLORD_ELECT("抢地主"), + + CODE_GAME_LANDLORD_CONFIRM("地主确认"), + + CODE_GAME_LANDLORD_CYCLE("地主一轮确认结束"), + + CODE_GAME_POKER_PLAY("出牌回合"), + + CODE_GAME_POKER_PLAY_REDIRECT("出牌重定向"), + + CODE_GAME_POKER_PLAY_MISMATCH("出牌不匹配"), + + CODE_GAME_POKER_PLAY_LESS("出牌太小"), + + CODE_GAME_POKER_PLAY_PASS("不出"), + + CODE_GAME_POKER_PLAY_CANT_PASS("不允许不出"), + + CODE_GAME_POKER_PLAY_INVALID("无效"), + + CODE_GAME_POKER_PLAY_ORDER_ERROR("顺序错误"), + + CODE_GAME_OVER("游戏结束"), + + CODE_PVE_DIFFICULTY_NOT_SUPPORT("人机难度不支持"), + + CODE_GAME_READY("准备开始游戏"), + + CODE_GAME_WATCH("观战"), + + CODE_GAME_WATCH_SUCCESSFUL("观战成功"); + + private String msg; + + private ClientEventCode(String msg) { + this.msg = msg; + } + + public final String getMsg() { + return msg; + } + + public final void setMsg(String msg) { + this.msg = msg; + } + +} diff --git a/landlords-common/src/main/java/org/nico/ratel/landlords/enums/ClientRole.java b/landlords-common/src/main/java/org/nico/ratel/landlords/enums/ClientRole.java new file mode 100644 index 0000000..38ba214 --- /dev/null +++ b/landlords-common/src/main/java/org/nico/ratel/landlords/enums/ClientRole.java @@ -0,0 +1,9 @@ +package org.nico.ratel.landlords.enums; + +public enum ClientRole { + + PLAYER, + + ROBOT + +} diff --git a/landlords-common/src/main/java/org/nico/ratel/landlords/enums/ClientStatus.java b/landlords-common/src/main/java/org/nico/ratel/landlords/enums/ClientStatus.java new file mode 100644 index 0000000..efbf92e --- /dev/null +++ b/landlords-common/src/main/java/org/nico/ratel/landlords/enums/ClientStatus.java @@ -0,0 +1,18 @@ +package org.nico.ratel.landlords.enums; + +public enum ClientStatus { + + TO_CHOOSE, + + NO_READY, + + READY, + + WAIT, + + CALL_LANDLORD, + + PLAYING + + +} diff --git a/landlords-common/src/main/java/org/nico/ratel/landlords/enums/ClientType.java b/landlords-common/src/main/java/org/nico/ratel/landlords/enums/ClientType.java new file mode 100644 index 0000000..868a901 --- /dev/null +++ b/landlords-common/src/main/java/org/nico/ratel/landlords/enums/ClientType.java @@ -0,0 +1,9 @@ +package org.nico.ratel.landlords.enums; + +public enum ClientType { + + LANDLORD, + + PEASANT + +} diff --git a/landlords-common/src/main/java/org/nico/ratel/landlords/enums/PokerLevel.java b/landlords-common/src/main/java/org/nico/ratel/landlords/enums/PokerLevel.java new file mode 100644 index 0000000..e2f96a4 --- /dev/null +++ b/landlords-common/src/main/java/org/nico/ratel/landlords/enums/PokerLevel.java @@ -0,0 +1,113 @@ +package org.nico.ratel.landlords.enums; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +/** + * Poker level + * + * @author nico + */ +public enum PokerLevel { + + LEVEL_3(3, "3", new Character[]{'3'}), + + LEVEL_4(4, "4", new Character[]{'4'}), + + LEVEL_5(5, "5", new Character[]{'5'}), + + LEVEL_6(6, "6", new Character[]{'6'}), + + LEVEL_7(7, "7", new Character[]{'7'}), + + LEVEL_8(8, "8", new Character[]{'8'}), + + LEVEL_9(9, "9", new Character[]{'9'}), + + LEVEL_10(10, "10", new Character[]{'T', 't', '0'}), + + LEVEL_J(11, "J", new Character[]{'J', 'j'}), + + LEVEL_Q(12, "Q", new Character[]{'Q', 'q'}), + + LEVEL_K(13, "K", new Character[]{'K', 'k'}), + + LEVEL_A(14, "A", new Character[]{'A', 'a', '1'}), + + LEVEL_2(15, "2", new Character[]{'2'}), + + LEVEL_SMALL_KING(16, "S", new Character[]{'S', 's'}), + + LEVEL_BIG_KING(17, "X", new Character[]{'X', 'x'}), + ; + + private int level; + + private String name; + + private Character[] alias; + + private static Set aliasSet = new HashSet<>(); + + static { + for (PokerLevel level : PokerLevel.values()) { + PokerLevel.aliasSet.addAll(Arrays.asList(level.getAlias())); + } + } + + private PokerLevel(int level, String name, Character[] alias) { + this.level = level; + this.name = name; + this.alias = alias; + } + + public static boolean aliasContains(char key) { + return aliasSet.contains(key); + } + + public final Character[] getAlias() { + return alias; + } + + public final void setAlias(Character[] alias) { + this.alias = alias; + } + + public final String getName() { + return name; + } + + public final void setName(String name) { + this.name = name; + } + + public final int getLevel() { + return level; + } + + public final void setLevel(int level) { + this.level = level; + } + + public static final PokerLevel parseByName(String name) { + if(name == null) { + return null; + } + for(PokerLevel level: PokerLevel.values()) { + if(level.name.equals(name.toUpperCase())) { + return level; + } + } + return null; + } + + public static final PokerLevel parseByLevel(int l) { + for(PokerLevel level: PokerLevel.values()) { + if(level.level == l) { + return level; + } + } + return null; + } +} diff --git a/landlords-common/src/main/java/org/nico/ratel/landlords/enums/PokerType.java b/landlords-common/src/main/java/org/nico/ratel/landlords/enums/PokerType.java new file mode 100644 index 0000000..fd6dc6a --- /dev/null +++ b/landlords-common/src/main/java/org/nico/ratel/landlords/enums/PokerType.java @@ -0,0 +1,29 @@ +package org.nico.ratel.landlords.enums; + +/** + * Poker type Spade、 Heart、 Diamond、 Club + * + * @author nico + */ +public enum PokerType { + + BLANK(" "), + + DIAMOND("♦"), + + CLUB("♣"), + + SPADE("♠"), + + HEART("♥"); + + private final String name; + + PokerType(String name) { + this.name = name; + } + + public final String getName() { + return name; + } +} diff --git a/landlords-common/src/main/java/org/nico/ratel/landlords/enums/RoomStatus.java b/landlords-common/src/main/java/org/nico/ratel/landlords/enums/RoomStatus.java new file mode 100644 index 0000000..68f5b2a --- /dev/null +++ b/landlords-common/src/main/java/org/nico/ratel/landlords/enums/RoomStatus.java @@ -0,0 +1,28 @@ +package org.nico.ratel.landlords.enums; + +public enum RoomStatus { + + BLANK("空闲"), + + WAIT("等待"), + + STARTING("开始"), + + + ; + + private String msg; + + RoomStatus(String msg) { + this.msg = msg; + } + + public final String getMsg() { + return msg; + } + + public final void setMsg(String msg) { + this.msg = msg; + } + +} diff --git a/landlords-common/src/main/java/org/nico/ratel/landlords/enums/RoomType.java b/landlords-common/src/main/java/org/nico/ratel/landlords/enums/RoomType.java new file mode 100644 index 0000000..601aa73 --- /dev/null +++ b/landlords-common/src/main/java/org/nico/ratel/landlords/enums/RoomType.java @@ -0,0 +1,24 @@ +package org.nico.ratel.landlords.enums; + +public enum RoomType { + + PVP("玩家对战"), + + PVE("人机对战"), + + ; + private String msg; + + RoomType(String msg) { + this.msg = msg; + } + + public final String getMsg() { + return msg; + } + + public final void setMsg(String msg) { + this.msg = msg; + } + +} diff --git a/landlords-common/src/main/java/org/nico/ratel/landlords/enums/SellType.java b/landlords-common/src/main/java/org/nico/ratel/landlords/enums/SellType.java new file mode 100644 index 0000000..fc41b35 --- /dev/null +++ b/landlords-common/src/main/java/org/nico/ratel/landlords/enums/SellType.java @@ -0,0 +1,56 @@ +package org.nico.ratel.landlords.enums; + +public enum SellType { + + ILLEGAL("非合法"), + + BOMB("炸弹"), + + KING_BOMB("王炸"), + + SINGLE("单个牌"), + + DOUBLE("对子牌"), + + THREE("三张牌"), + + THREE_ZONES_SINGLE("三带单"), + + THREE_ZONES_DOUBLE("三带对"), + + FOUR_ZONES_SINGLE("四带单"), + + FOUR_ZONES_DOUBLE("四带对"), + + SINGLE_STRAIGHT("单顺子"), + + DOUBLE_STRAIGHT("双顺子"), + + THREE_STRAIGHT("三顺子"), + + FOUR_STRAIGHT("四顺子"), + + THREE_STRAIGHT_WITH_SINGLE("飞机带单牌"), + + THREE_STRAIGHT_WITH_DOUBLE("飞机带对牌"), + + FOUR_STRAIGHT_WITH_SINGLE("四顺子带单"), + + FOUR_STRAIGHT_WITH_DOUBLE("四顺子带对"), + ; + + private String msg; + + SellType(String msg) { + this.msg = msg; + } + + public final String getMsg() { + return msg; + } + + public final void setMsg(String msg) { + this.msg = msg; + } + +} diff --git a/landlords-common/src/main/java/org/nico/ratel/landlords/enums/ServerEventCode.java b/landlords-common/src/main/java/org/nico/ratel/landlords/enums/ServerEventCode.java new file mode 100644 index 0000000..b478890 --- /dev/null +++ b/landlords-common/src/main/java/org/nico/ratel/landlords/enums/ServerEventCode.java @@ -0,0 +1,56 @@ +package org.nico.ratel.landlords.enums; + +import java.io.Serializable; + +public enum ServerEventCode implements Serializable { + + CODE_CLIENT_EXIT("玩家退出"), + + CODE_CLIENT_OFFLINE("玩家离线"), + + CODE_CLIENT_INFO_SET("设置客户端信息"), + + CODE_CLIENT_NICKNAME_SET("设置昵称"), + + CODE_CLIENT_HEAD_BEAT("不出"), + + CODE_ROOM_CREATE("创建PVP房间"), + + CODE_ROOM_CREATE_PVE("创建PVE房间"), + + CODE_GET_ROOMS("获取房间列表"), + + CODE_ROOM_JOIN("加入房间"), + + CODE_GAME_STARTING("游戏开始"), + + CODE_GAME_READY("玩家准备"), + + CODE_GAME_LANDLORD_ELECT("抢地主"), + + CODE_GAME_POKER_PLAY("出牌环节"), + + CODE_GAME_POKER_PLAY_REDIRECT("出牌重定向"), + + CODE_GAME_POKER_PLAY_PASS("不出"), + + CODE_GAME_WATCH("观战"), + + CODE_GAME_WATCH_EXIT("退出观战"); + + + private String msg; + + ServerEventCode(String msg) { + this.msg = msg; + } + + public final String getMsg() { + return msg; + } + + public final void setMsg(String msg) { + this.msg = msg; + } + +} diff --git a/landlords-common/src/main/java/org/nico/ratel/landlords/exception/LandlordException.java b/landlords-common/src/main/java/org/nico/ratel/landlords/exception/LandlordException.java new file mode 100644 index 0000000..2643a2a --- /dev/null +++ b/landlords-common/src/main/java/org/nico/ratel/landlords/exception/LandlordException.java @@ -0,0 +1,27 @@ +package org.nico.ratel.landlords.exception; + +public class LandlordException extends RuntimeException { + + private static final long serialVersionUID = -5643145833569293539L; + + public LandlordException() { + super(); + } + + public LandlordException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } + + public LandlordException(String message, Throwable cause) { + super(message, cause); + } + + public LandlordException(String message) { + super(message); + } + + public LandlordException(Throwable cause) { + super(cause); + } + +} diff --git a/landlords-common/src/main/java/org/nico/ratel/landlords/features/Features.java b/landlords-common/src/main/java/org/nico/ratel/landlords/features/Features.java new file mode 100644 index 0000000..40b1db7 --- /dev/null +++ b/landlords-common/src/main/java/org/nico/ratel/landlords/features/Features.java @@ -0,0 +1,23 @@ +package org.nico.ratel.landlords.features; + +import java.util.*; + +public class Features { + + public final static String VERSION_1_3_0 = "v1.3.0"; + public final static String READY = "READY"; + private final static Map> FEATURES = new HashMap<>(); + + static{ + FEATURES.put(VERSION_1_3_0, Collections.singletonList(READY)); + } + + public static boolean supported(String clientVersion, String feature){ + List features = FEATURES.get(clientVersion); + if (Objects.isNull(features) || Objects.isNull(feature)){ + return false; + } + return features.contains(feature.toUpperCase(Locale.ROOT)); + } + +} diff --git a/landlords-common/src/main/java/org/nico/ratel/landlords/handler/DefaultDecoder.java b/landlords-common/src/main/java/org/nico/ratel/landlords/handler/DefaultDecoder.java new file mode 100644 index 0000000..60e2ef1 --- /dev/null +++ b/landlords-common/src/main/java/org/nico/ratel/landlords/handler/DefaultDecoder.java @@ -0,0 +1,27 @@ +package org.nico.ratel.landlords.handler; + +import java.util.List; + +import org.nico.ratel.landlords.transfer.TransferProtocolUtils; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.ByteToMessageDecoder; + +public class DefaultDecoder extends ByteToMessageDecoder { + + @Override + protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) { + int startIndex; + int endIndex; + if ((startIndex = in.indexOf(in.readerIndex(), in.writerIndex(), TransferProtocolUtils.PROTOCOL_HAED)) != -1 && + (endIndex = in.indexOf(startIndex + 1, in.writerIndex(), TransferProtocolUtils.PROTOCOL_TAIL)) != -1) { + endIndex++; + byte[] bytes = new byte[endIndex - startIndex]; + in.skipBytes(startIndex - in.readerIndex()); + in.readBytes(bytes, 0, bytes.length); + out.add(bytes); + } + } + +} diff --git a/landlords-common/src/main/java/org/nico/ratel/landlords/helper/MapHelper.java b/landlords-common/src/main/java/org/nico/ratel/landlords/helper/MapHelper.java new file mode 100644 index 0000000..84ce706 --- /dev/null +++ b/landlords-common/src/main/java/org/nico/ratel/landlords/helper/MapHelper.java @@ -0,0 +1,37 @@ +package org.nico.ratel.landlords.helper; + +import java.util.LinkedHashMap; +import java.util.Map; + +import org.nico.noson.Noson; + +public class MapHelper { + + private final Map data; + + private MapHelper() { + this.data = new LinkedHashMap<>(); + } + + public static MapHelper newInstance() { + return new MapHelper(); + } + + public static Map parser(String json) { + return Noson.convert(json, Map.class); + } + + public MapHelper put(String name, Object Object) { + this.data.put(name, Object); + return this; + } + + public String json() { + return Noson.reversal(data); + } + + public Map map() { + return data; + } + +} diff --git a/landlords-common/src/main/java/org/nico/ratel/landlords/helper/PokerHelper.java b/landlords-common/src/main/java/org/nico/ratel/landlords/helper/PokerHelper.java new file mode 100644 index 0000000..55eaf36 --- /dev/null +++ b/landlords-common/src/main/java/org/nico/ratel/landlords/helper/PokerHelper.java @@ -0,0 +1,632 @@ +package org.nico.ratel.landlords.helper; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.nico.ratel.landlords.entity.Poker; +import org.nico.ratel.landlords.entity.PokerSell; +import org.nico.ratel.landlords.enums.PokerLevel; +import org.nico.ratel.landlords.enums.PokerType; +import org.nico.ratel.landlords.enums.SellType; +import org.nico.ratel.landlords.utils.ListUtils; + +public class PokerHelper { + + /** + * Print the type of poker style + */ + public static int pokerPrinterType = 0; + + public static int totalPrinters = 5; + + /** + * The list of all pokers, by 54 + */ + private static final List basePokers = new ArrayList<>(54); + + private static final Comparator pokerComparator = (o1, o2) -> o1.getLevel().getLevel() - o2.getLevel().getLevel(); + + static { + PokerLevel[] pokerLevels = PokerLevel.values(); + PokerType[] pokerTypes = PokerType.values(); + + for (PokerLevel level : pokerLevels) { + if (level == PokerLevel.LEVEL_BIG_KING) { + basePokers.add(new Poker(level, PokerType.BLANK)); + continue; + } + if (level == PokerLevel.LEVEL_SMALL_KING) { + basePokers.add(new Poker(level, PokerType.BLANK)); + continue; + } + for (PokerType type : pokerTypes) { + if (type == PokerType.BLANK) { + continue; + } + basePokers.add(new Poker(level, type)); + } + } + } + + public static void sortPoker(List pokers) { + pokers.sort(pokerComparator); + } + + public static List clonePokers(List pokers){ + List newPokers = new ArrayList(pokers.size()); + for(Poker poker: pokers) { + newPokers.add(new Poker(poker.getLevel(), poker.getType())); + } + return newPokers; + } + + public static List validSells(PokerSell lastPokerSell, List pokers) { + List sells = PokerHelper.parsePokerSells(pokers); + if(lastPokerSell == null) { + return sells; + } + + List validSells = new ArrayList(); + for(PokerSell sell: sells) { + if(sell.getSellType() == lastPokerSell.getSellType()) { + if(sell.getScore() > lastPokerSell.getScore() && sell.getSellPokers().size() == lastPokerSell.getSellPokers().size()) { + validSells.add(sell); + } + } + if(sell.getSellType() == SellType.KING_BOMB) { + validSells.add(sell); + } + } + if(lastPokerSell.getSellType() != SellType.BOMB) { + for(PokerSell sell: sells) { + if(sell.getSellType() == SellType.BOMB) { + validSells.add(sell); + } + } + } + return validSells; + } + + public static int[] getIndexes(Character[] options, List pokers) { + List copyList = new ArrayList<>(pokers.size()); + copyList.addAll(pokers); + int[] indexes = new int[options.length]; + for (int index = 0; index < options.length; index++) { + char option = options[index]; + boolean isTarget = false; + for (int pi = 0; pi < copyList.size(); pi++) { + Poker poker = copyList.get(pi); + if (poker == null) { + continue; + } + if (Arrays.asList(poker.getLevel().getAlias()).contains(option)) { + isTarget = true; + //Index start from 1, not 0 + indexes[index] = pi + 1; + copyList.set(pi, null); + break; + } + } + if (!isTarget) { + return null; + } + } + Arrays.sort(indexes); + return indexes; + } + + public static boolean checkPokerIndex(int[] indexes, List pokers) { + if (indexes == null || indexes.length == 0) { + return false; + } + for (int index : indexes) { + if (index > pokers.size() || index < 1) { + return false; + } + } + return true; + } + + public static PokerSell checkPokerType(List pokers) { + if (pokers == null || pokers.isEmpty()) { + return new PokerSell(SellType.ILLEGAL, null, -1); + } + sortPoker(pokers); + + int[] levelTable = new int[20]; + for (Poker poker : pokers) { + levelTable[poker.getLevel().getLevel()]++; + } + + int startIndex = -1; + int endIndex = -1; + int count = 0; + + int singleCount = 0; + int doubleCount = 0; + int threeCount = 0; + int threeStartIndex = -1; + int threeEndIndex = -1; + int fourCount = 0; + int fourStartIndex = -1; + int fourEndIndex = -1; + for (int index = 0; index < levelTable.length; index++) { + int value = levelTable[index]; + if (value == 0) { + continue; + } + endIndex = index; + count++; + if (startIndex == -1) { + startIndex = index; + } + if (value == 1) { + singleCount++; + } else if (value == 2) { + doubleCount++; + } else if (value == 3) { + if (threeStartIndex == -1) { + threeStartIndex = index; + } + threeEndIndex = index; + threeCount++; + } else if (value == 4) { + if (fourStartIndex == -1) { + fourStartIndex = index; + } + fourEndIndex = index; + fourCount++; + } + } + + if (singleCount == doubleCount && singleCount == threeCount && singleCount == 0 && fourCount == 1) { + return new PokerSell(SellType.BOMB, pokers, startIndex); + } + + if (singleCount == 2 && startIndex == PokerLevel.LEVEL_SMALL_KING.getLevel() && endIndex == PokerLevel.LEVEL_BIG_KING.getLevel()) { + return new PokerSell(SellType.KING_BOMB, pokers, PokerLevel.LEVEL_SMALL_KING.getLevel()); + } + + if (startIndex == endIndex) { + if (levelTable[startIndex] == 1) { + return new PokerSell(SellType.SINGLE, pokers, startIndex); + } else if (levelTable[startIndex] == 2) { + return new PokerSell(SellType.DOUBLE, pokers, startIndex); + } else if (levelTable[startIndex] == 3) { + return new PokerSell(SellType.THREE, pokers, startIndex); + } + } + if (endIndex - startIndex == count - 1 && endIndex < PokerLevel.LEVEL_2.getLevel()) { + if (levelTable[startIndex] == 1 && singleCount > 4 && doubleCount + threeCount + fourCount == 0) { + return new PokerSell(SellType.SINGLE_STRAIGHT, pokers, endIndex); + } else if (levelTable[startIndex] == 2 && doubleCount > 2 && singleCount + threeCount + fourCount == 0) { + return new PokerSell(SellType.DOUBLE_STRAIGHT, pokers, endIndex); + } else if (levelTable[startIndex] == 3 && threeCount > 1 && doubleCount + singleCount + fourCount == 0) { + return new PokerSell(SellType.THREE_STRAIGHT, pokers, endIndex); + } else if (levelTable[startIndex] == 4 && fourCount > 1 && doubleCount + threeCount + singleCount == 0) { + return new PokerSell(SellType.FOUR_STRAIGHT, pokers, endIndex); + } + } + + if (threeCount != 0) { + if (singleCount != 0 && singleCount == threeCount && doubleCount == 0 && fourCount == 0) { + if (threeCount == 1) { + return new PokerSell(SellType.THREE_ZONES_SINGLE, pokers, threeEndIndex); + } + if (threeEndIndex - threeStartIndex + 1 == threeCount && threeEndIndex < PokerLevel.LEVEL_2.getLevel()) { + return new PokerSell(SellType.THREE_STRAIGHT_WITH_SINGLE, pokers, threeEndIndex); + } + } else if (doubleCount != 0 && doubleCount == threeCount && singleCount == 0 && fourCount == 0) { + if (threeCount == 1) { + return new PokerSell(SellType.THREE_ZONES_DOUBLE, pokers, threeEndIndex); + } + if (threeEndIndex - threeStartIndex + 1 == threeCount && threeEndIndex < PokerLevel.LEVEL_2.getLevel()) { + return new PokerSell(SellType.THREE_STRAIGHT_WITH_DOUBLE, pokers, threeEndIndex); + } + } else if (singleCount + doubleCount * 2 == threeCount && fourCount == 0) { + return new PokerSell(SellType.THREE_STRAIGHT_WITH_SINGLE, pokers, threeEndIndex); + } + } + + if (fourCount != 0) { + if (singleCount != 0 && singleCount == fourCount * 2 && doubleCount == 0 && threeCount == 0) { + if (fourCount == 1) { + return new PokerSell(SellType.FOUR_ZONES_SINGLE, pokers, fourEndIndex); + } + if (fourEndIndex - fourStartIndex + 1 == fourCount && fourEndIndex < PokerLevel.LEVEL_2.getLevel()) { + return new PokerSell(SellType.FOUR_STRAIGHT_WITH_SINGLE, pokers, fourEndIndex); + } + } else if (doubleCount != 0 && doubleCount == fourCount * 2 && singleCount == 0 && threeCount == 0) { + if (fourCount == 1) { + return new PokerSell(SellType.FOUR_ZONES_DOUBLE, pokers, fourEndIndex); + } + if (fourEndIndex - fourStartIndex + 1 == fourCount && fourEndIndex < PokerLevel.LEVEL_2.getLevel()) { + return new PokerSell(SellType.FOUR_STRAIGHT_WITH_DOUBLE, pokers, fourEndIndex); + } + } + } + return new PokerSell(SellType.ILLEGAL, null, -1); + } + + public static int parseScore(SellType sellType, int level) { + if (sellType == SellType.BOMB) { + return level * 4 + 999; + } else if (sellType == SellType.KING_BOMB) { + return Integer.MAX_VALUE; + } else if (sellType == SellType.SINGLE || sellType == SellType.DOUBLE || sellType == SellType.THREE) { + return level; + } else if (sellType == SellType.SINGLE_STRAIGHT || sellType == SellType.DOUBLE_STRAIGHT || sellType == SellType.THREE_STRAIGHT || sellType == SellType.FOUR_STRAIGHT) { + return level; + } else if (sellType == SellType.THREE_ZONES_SINGLE || sellType == SellType.THREE_STRAIGHT_WITH_SINGLE || sellType == SellType.THREE_ZONES_DOUBLE || sellType == SellType.THREE_STRAIGHT_WITH_DOUBLE) { + return level; + } else if (sellType == SellType.FOUR_ZONES_SINGLE || sellType == SellType.FOUR_STRAIGHT_WITH_SINGLE || sellType == SellType.FOUR_ZONES_DOUBLE || sellType == SellType.FOUR_STRAIGHT_WITH_DOUBLE) { + return level; + } + return -1; + } + + public static List getPoker(int[] indexes, List pokers) { + List resultPokers = new ArrayList<>(indexes.length); + for (int index : indexes) { + resultPokers.add(pokers.get(index - 1)); + } + sortPoker(resultPokers); + return resultPokers; + } + + public static boolean comparePoker(List pres, List currents) { + + return true; + } + + public static List> distributePoker() { + Collections.shuffle(basePokers); + List> pokersList = new ArrayList>(); + List pokers1 = new ArrayList<>(17); + pokers1.addAll(basePokers.subList(0, 17)); + List pokers2 = new ArrayList<>(17); + pokers2.addAll(basePokers.subList(17, 34)); + List pokers3 = new ArrayList<>(17); + pokers3.addAll(basePokers.subList(34, 51)); + List pokers4 = new ArrayList<>(3); + pokers4.addAll(basePokers.subList(51, 54)); + pokersList.add(pokers1); + pokersList.add(pokers2); + pokersList.add(pokers3); + pokersList.add(pokers4); + for (List pokers : pokersList) { + sortPoker(pokers); + } + return pokersList; + } + + public static String printPoker(List pokers) { + sortPoker(pokers); + switch (pokerPrinterType) { + case 0: + return buildHandStringSharp(pokers); + case 1: + return buildHandStringRounded(pokers); + case 2: + return textOnly(pokers); + case 3: + return textOnlyNoType(pokers); + default: + return buildHandStringSharp(pokers); + + } + + } + + private static String buildHandStringSharp(List pokers) { + StringBuilder builder = new StringBuilder(); + if (pokers != null && pokers.size() > 0) { + + for (int index = 0; index < pokers.size(); index++) { + if (index == 0) { + builder.append("┌──┐"); + } else { + builder.append("──┐"); + } + } + builder.append(System.lineSeparator()); + for (int index = 0; index < pokers.size(); index++) { + if (index == 0) { + builder.append("│"); + } + String name = pokers.get(index).getLevel().getName(); + builder.append(name).append(name.length() == 1 ? " " : "").append("|"); + } + builder.append(System.lineSeparator()); + for (int index = 0; index < pokers.size(); index++) { + if (index == 0) { + builder.append("│"); + } + builder.append(pokers.get(index).getType().getName()).append(" |"); + } + builder.append(System.lineSeparator()); + for (int index = 0; index < pokers.size(); index++) { + if (index == 0) { + builder.append("└──┘"); + } else { + builder.append("──┘"); + } + } + } + return builder.toString(); + } + + private static String buildHandStringRounded(List pokers) { + StringBuilder builder = new StringBuilder(); + if (pokers != null && pokers.size() > 0) { + + for (int index = 0; index < pokers.size(); index++) { + if (index == 0) { + builder.append("┌──╮"); + } else { + builder.append("──╮"); + } + } + builder.append(System.lineSeparator()); + for (int index = 0; index < pokers.size(); index++) { + if (index == 0) { + builder.append("│"); + } + String name = pokers.get(index).getLevel().getName(); + builder.append(name).append(name.length() == 1 ? " " : "").append("|"); + } + builder.append(System.lineSeparator()); + for (int index = 0; index < pokers.size(); index++) { + if (index == 0) { + builder.append("│"); + } + builder.append(pokers.get(index).getType().getName()).append(" |"); + } + builder.append(System.lineSeparator()); + for (int index = 0; index < pokers.size(); index++) { + if (index == 0) { + builder.append("└──╯"); + } else { + builder.append("──╯"); + } + } + } + return builder.toString(); + } + + private static String textOnly(List pokers) { + StringBuilder builder = new StringBuilder(); + if (pokers != null && pokers.size() > 0) { + for (Poker poker : pokers) { + String name = poker.getLevel().getName(); + String type = poker.getType().getName(); + + builder.append(name).append(type); + } + } + return builder.toString(); + } + + public static String textOnlyNoType(List pokers) { + StringBuilder builder = new StringBuilder(); + if (pokers != null && pokers.size() > 0) { + for (Poker poker : pokers) { + String name = poker.getLevel().getName(); + builder.append(name).append(" "); + } + } + return builder.toString(); + } + + public static int parsePokerColligationScore(List pokers) { + int score = 0; + int count = 0; + int increase = 0; + int lastLevel = -1; + if (pokers != null && !pokers.isEmpty()) { + for (int index = 0; index < pokers.size(); index++) { + int level = pokers.get(index).getLevel().getLevel(); + if (lastLevel == -1) { + increase++; + count++; + score += lastLevel; + } else { + if (level == lastLevel) { + ++count; + } else { + count = 1; + } + if (level < PokerLevel.LEVEL_2.getLevel() && level - 1 == lastLevel) { + ++increase; + } else { + increase = 1; + } + + score += (count + (increase > 4 ? increase : 0)) * level; + } + + if (level == PokerLevel.LEVEL_2.getLevel()) { + score += level * 2; + } else if (level > PokerLevel.LEVEL_2.getLevel()) { + score += level * 3; + } + lastLevel = level; + } + } + return score; + } + + public static List parsePokerSells(List pokers) { + List pokerSells = new ArrayList<>(); + int size = pokers.size(); + + //all single or double + { + int count = 0; + int lastLevel = -1; + List sellPokers = new ArrayList<>(4); + for (Poker poker : pokers) { + int level = poker.getLevel().getLevel(); + if (lastLevel == -1) { + ++count; + } else { + if (level == lastLevel) { + ++count; + } else { + count = 1; + sellPokers.clear(); + } + } + sellPokers.add(poker); + if (count == 1) { + pokerSells.add(new PokerSell(SellType.SINGLE, ListUtils.getList(sellPokers), poker.getLevel().getLevel())); + } else if (count == 2) { + pokerSells.add(new PokerSell(SellType.DOUBLE, ListUtils.getList(sellPokers), poker.getLevel().getLevel())); + } else if (count == 3) { + pokerSells.add(new PokerSell(SellType.THREE, ListUtils.getList(sellPokers), poker.getLevel().getLevel())); + } else if (count == 4) { + pokerSells.add(new PokerSell(SellType.BOMB, ListUtils.getList(sellPokers), poker.getLevel().getLevel())); + } + + lastLevel = level; + } + } + //Shunzi + { + parsePokerSellStraight(pokerSells, SellType.SINGLE); + parsePokerSellStraight(pokerSells, SellType.DOUBLE); + parsePokerSellStraight(pokerSells, SellType.THREE); + parsePokerSellStraight(pokerSells, SellType.BOMB); + } + + //Shunzi with args + { + for (int index = 0; index < pokerSells.size(); index++) { + PokerSell sell = pokerSells.get(index); + if (sell.getSellType() == SellType.THREE) { + parseArgs(pokerSells, sell, 1, SellType.SINGLE, SellType.THREE_ZONES_SINGLE); + parseArgs(pokerSells, sell, 1, SellType.DOUBLE, SellType.THREE_ZONES_DOUBLE); + } else if (sell.getSellType() == SellType.BOMB) { + parseArgs(pokerSells, sell, 2, SellType.SINGLE, SellType.FOUR_ZONES_SINGLE); + parseArgs(pokerSells, sell, 2, SellType.DOUBLE, SellType.FOUR_ZONES_DOUBLE); + } else if (sell.getSellType() == SellType.THREE_STRAIGHT) { + int count = sell.getSellPokers().size() / 3; + parseArgs(pokerSells, sell, count, SellType.SINGLE, SellType.THREE_STRAIGHT_WITH_SINGLE); + parseArgs(pokerSells, sell, count, SellType.DOUBLE, SellType.THREE_STRAIGHT_WITH_DOUBLE); + } else if (sell.getSellType() == SellType.FOUR_STRAIGHT) { + int count = (sell.getSellPokers().size() / 4) * 2; + parseArgs(pokerSells, sell, count, SellType.SINGLE, SellType.FOUR_STRAIGHT_WITH_SINGLE); + parseArgs(pokerSells, sell, count, SellType.DOUBLE, SellType.FOUR_STRAIGHT_WITH_DOUBLE); + } + } + } + + //king boom + { + if (size > 1) { + if (pokers.get(size - 1).getLevel() == PokerLevel.LEVEL_BIG_KING && pokers.get(size - 2).getLevel() == PokerLevel.LEVEL_SMALL_KING) { + pokerSells.add(new PokerSell(SellType.KING_BOMB, ListUtils.getList(new Poker[]{pokers.get(size - 2), pokers.get(size - 1)}), PokerLevel.LEVEL_BIG_KING.getLevel())); + } + } + } + + return pokerSells; + } + + private static void parseArgs(List pokerSells, PokerSell pokerSell, int deep, SellType sellType, SellType targetSellType) { + Set existLevelSet = new HashSet<>(); + for (Poker p : pokerSell.getSellPokers()) { + existLevelSet.add(p.getLevel().getLevel()); + } + parseArgs(existLevelSet, pokerSells, new HashSet<>(), pokerSell, deep, sellType, targetSellType); + } + + private static void parseArgs(Set existLevelSet, List pokerSells, Set> pokersList, PokerSell pokerSell, int deep, SellType sellType, SellType targetSellType) { + if (deep == 0) { + List allPokers = new ArrayList<>(pokerSell.getSellPokers()); + for (List ps : pokersList) { + allPokers.addAll(ps); + } + pokerSells.add(new PokerSell(targetSellType, allPokers, pokerSell.getCoreLevel())); + return; + } + + for (int index = 0; index < pokerSells.size(); index++) { + PokerSell subSell = pokerSells.get(index); + if (subSell.getSellType() == sellType && !existLevelSet.contains(subSell.getCoreLevel())) { + pokersList.add(subSell.getSellPokers()); + existLevelSet.add(subSell.getCoreLevel()); + parseArgs(existLevelSet, pokerSells, pokersList, pokerSell, deep - 1, sellType, targetSellType); + existLevelSet.remove(subSell.getCoreLevel()); + pokersList.remove(subSell.getSellPokers()); + } + } + } + + private static void parsePokerSellStraight(List pokerSells, SellType sellType) { + int minLength = -1; + int width = -1; + SellType targetSellType = null; + if (sellType == SellType.SINGLE) { + minLength = 5; + width = 1; + targetSellType = SellType.SINGLE_STRAIGHT; + } else if (sellType == SellType.DOUBLE) { + minLength = 3; + width = 2; + targetSellType = SellType.DOUBLE_STRAIGHT; + } else if (sellType == SellType.THREE) { + minLength = 2; + width = 3; + targetSellType = SellType.THREE_STRAIGHT; + } else if (sellType == SellType.BOMB) { + minLength = 2; + width = 4; + targetSellType = SellType.FOUR_STRAIGHT; + } + + int increase_1 = 0; + int lastLevel_1 = -1; + List sellPokers_1 = new ArrayList<>(4); + for (int index = 0; index < pokerSells.size(); index++) { + PokerSell sell = pokerSells.get(index); + + if (sell.getSellType() != sellType) { + continue; + } + int level = sell.getCoreLevel(); + if (lastLevel_1 == -1) { + ++increase_1; + } else { + if (level - 1 == lastLevel_1 && level != PokerLevel.LEVEL_2.getLevel()) { + ++increase_1; + } else { + addPokers(pokerSells, minLength, width, targetSellType, increase_1, sellPokers_1); + + increase_1 = 1; + } + } + sellPokers_1.addAll(sell.getSellPokers()); + lastLevel_1 = level; + } + addPokers(pokerSells, minLength, width, targetSellType, increase_1, sellPokers_1); + } + + private static void addPokers(List pokerSells, int minLenght, int width, SellType targetSellType, int increase_1, List sellPokers_1) { + if (increase_1 >= minLenght) { + for (int s = 0; s <= increase_1 - minLenght; s++) { + int len = minLenght + s; + for (int subIndex = 0; subIndex <= increase_1 - len; subIndex++) { + List pokers = ListUtils.getList(sellPokers_1.subList(subIndex * width, (subIndex + len) * width)); + pokerSells.add(new PokerSell(targetSellType, pokers, pokers.get(pokers.size() - 1).getLevel().getLevel())); + } + } + } + sellPokers_1.clear(); + } +} diff --git a/landlords-common/src/main/java/org/nico/ratel/landlords/helper/TimeHelper.java b/landlords-common/src/main/java/org/nico/ratel/landlords/helper/TimeHelper.java new file mode 100644 index 0000000..fa076ab --- /dev/null +++ b/landlords-common/src/main/java/org/nico/ratel/landlords/helper/TimeHelper.java @@ -0,0 +1,17 @@ +package org.nico.ratel.landlords.helper; + +/** + * + * @author nico + * @version createTime:2018年11月4日 下午6:29:32 + */ + +public class TimeHelper { + + public static void sleep(long millis) { + try { + Thread.sleep(millis); + } catch (InterruptedException ignored) { + } + } +} diff --git a/landlords-common/src/main/java/org/nico/ratel/landlords/print/FormatPrinter.java b/landlords-common/src/main/java/org/nico/ratel/landlords/print/FormatPrinter.java new file mode 100644 index 0000000..20f62fe --- /dev/null +++ b/landlords-common/src/main/java/org/nico/ratel/landlords/print/FormatPrinter.java @@ -0,0 +1,11 @@ +package org.nico.ratel.landlords.print; + +public class FormatPrinter { + + private FormatPrinter() { + } + + public static void printNotice(String format, Object... args) { + System.out.printf(format, args); + } +} diff --git a/landlords-common/src/main/java/org/nico/ratel/landlords/print/SimplePrinter.java b/landlords-common/src/main/java/org/nico/ratel/landlords/print/SimplePrinter.java new file mode 100644 index 0000000..5127458 --- /dev/null +++ b/landlords-common/src/main/java/org/nico/ratel/landlords/print/SimplePrinter.java @@ -0,0 +1,37 @@ +package org.nico.ratel.landlords.print; + +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.HashMap; + +import org.nico.ratel.landlords.entity.Poker; +import org.nico.ratel.landlords.helper.PokerHelper; + +public class SimplePrinter { + + private final static SimpleDateFormat FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + public static int pokerDisplayFormat = 0; + + public static void printPokers(List pokers) { + System.out.println(PokerHelper.printPoker(pokers)); + } + + public static void printNotice(String msg) { + System.out.println(msg); + } + + public static void printNotice(String msgKey, String locale) { + //TODO : read locale + Map> map = new HashMap<>(); + map.put("english", new HashMap<>()); + map.get("eng").put("caterpillar", "caterpillar's message!!"); + + System.out.println(map.get(locale).get(msgKey)); + } + + public static void serverLog(String msg) { + System.out.println(FORMAT.format(new Date()) + "-> " + msg); + } +} diff --git a/landlords-common/src/main/java/org/nico/ratel/landlords/print/SimpleWriter.java b/landlords-common/src/main/java/org/nico/ratel/landlords/print/SimpleWriter.java new file mode 100644 index 0000000..231deed --- /dev/null +++ b/landlords-common/src/main/java/org/nico/ratel/landlords/print/SimpleWriter.java @@ -0,0 +1,33 @@ +package org.nico.ratel.landlords.print; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; + +public class SimpleWriter { + + private static final BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); + + public static String write(String message) { + return write("player", message); + } + + public static String write(String nickname, String message) { + System.out.println(); + System.out.printf("[%s@%s]$ ", nickname, message); + try { + return write(); + } finally { + System.out.println(); + } + } + + public static String write() { + try { + return reader.readLine(); + } catch (IOException e) { + e.printStackTrace(); + } + return null; + } +} diff --git a/landlords-common/src/main/java/org/nico/ratel/landlords/robot/AbstractRobotDecisionMakers.java b/landlords-common/src/main/java/org/nico/ratel/landlords/robot/AbstractRobotDecisionMakers.java new file mode 100644 index 0000000..316a2c5 --- /dev/null +++ b/landlords-common/src/main/java/org/nico/ratel/landlords/robot/AbstractRobotDecisionMakers.java @@ -0,0 +1,20 @@ +package org.nico.ratel.landlords.robot; + +import java.util.List; + +import org.nico.ratel.landlords.entity.ClientSide; +import org.nico.ratel.landlords.entity.Poker; +import org.nico.ratel.landlords.entity.PokerSell; + +/** + * + * @author nico + * @version createTime:2018年11月15日 上午12:12:15 + */ + +public abstract class AbstractRobotDecisionMakers { + + public abstract PokerSell howToPlayPokers(PokerSell lastPokerSell, ClientSide robot); + + public abstract boolean howToChooseLandlord(List leftPokers, List rightPokers, List myPokers); +} diff --git a/landlords-common/src/main/java/org/nico/ratel/landlords/robot/EasyRobotDecisionMakers.java b/landlords-common/src/main/java/org/nico/ratel/landlords/robot/EasyRobotDecisionMakers.java new file mode 100644 index 0000000..3bc18d5 --- /dev/null +++ b/landlords-common/src/main/java/org/nico/ratel/landlords/robot/EasyRobotDecisionMakers.java @@ -0,0 +1,60 @@ +package org.nico.ratel.landlords.robot; + +import java.util.List; +import java.util.Random; + +import org.nico.ratel.landlords.entity.ClientSide; +import org.nico.ratel.landlords.entity.Poker; +import org.nico.ratel.landlords.entity.PokerSell; +import org.nico.ratel.landlords.enums.SellType; +import org.nico.ratel.landlords.helper.PokerHelper; + +/** + * @author nico + * @date 2018-11-15 12:13:49 + */ +public class EasyRobotDecisionMakers extends AbstractRobotDecisionMakers { + + private static Random random = new Random(); + + @Override + public PokerSell howToPlayPokers(PokerSell lastPokerSell, ClientSide robot) { + if (lastPokerSell != null && lastPokerSell.getSellType() == SellType.KING_BOMB) { + return null; + } + + List sells = PokerHelper.parsePokerSells(robot.getPokers()); + if (lastPokerSell == null) { + return sells.get(random.nextInt(sells.size())); + } + + for (PokerSell sell : sells) { + if (sell.getSellType() == lastPokerSell.getSellType()) { + if (sell.getScore() > lastPokerSell.getScore() && sell.getSellPokers().size() == lastPokerSell.getSellPokers().size()) { + return sell; + } + } + } + if (lastPokerSell.getSellType() != SellType.BOMB) { + for (PokerSell sell : sells) { + if (sell.getSellType() == SellType.BOMB) { + return sell; + } + } + } + for (PokerSell sell : sells) { + if (sell.getSellType() == SellType.KING_BOMB) { + return sell; + } + } + return null; + } + + @Override + public boolean howToChooseLandlord(List leftPokers, List rightPokers, List myPokers) { + List leftSells = PokerHelper.parsePokerSells(leftPokers); + List mySells = PokerHelper.parsePokerSells(myPokers); + List rightSells = PokerHelper.parsePokerSells(rightPokers); + return mySells.size() > leftSells.size() && mySells.size() > rightSells.size(); + } +} diff --git a/landlords-common/src/main/java/org/nico/ratel/landlords/robot/MediumRobotDecisionMakers.java b/landlords-common/src/main/java/org/nico/ratel/landlords/robot/MediumRobotDecisionMakers.java new file mode 100644 index 0000000..959f497 --- /dev/null +++ b/landlords-common/src/main/java/org/nico/ratel/landlords/robot/MediumRobotDecisionMakers.java @@ -0,0 +1,139 @@ +package org.nico.ratel.landlords.robot; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicLong; + +import org.nico.ratel.landlords.entity.ClientSide; +import org.nico.ratel.landlords.entity.Poker; +import org.nico.ratel.landlords.entity.PokerSell; +import org.nico.ratel.landlords.enums.SellType; +import org.nico.ratel.landlords.helper.PokerHelper; + + +/** + * Trial game algorithm + * + * @author nico + * @date 2020-12-19 16:36 + */ +public class MediumRobotDecisionMakers extends AbstractRobotDecisionMakers { + + private static final Long DEDUCE_LIMIT = 100 * 3L; + + public MediumRobotDecisionMakers() {} + + @Override + public PokerSell howToPlayPokers(PokerSell lastPokerSell, ClientSide robot) { + if(lastPokerSell != null && lastPokerSell.getSellType() == SellType.KING_BOMB) { + return null; + } + List selfPoker = PokerHelper.clonePokers(robot.getPokers()); + List leftPoker = PokerHelper.clonePokers(robot.getPre().getPokers()); + List rightPoker = PokerHelper.clonePokers(robot.getNext().getPokers()); + PokerHelper.sortPoker(selfPoker); + PokerHelper.sortPoker(leftPoker); + PokerHelper.sortPoker(rightPoker); + + List> pokersList = new ArrayList>(); + pokersList.add(selfPoker); + pokersList.add(rightPoker); + pokersList.add(leftPoker); + + List sells = PokerHelper.validSells(lastPokerSell, selfPoker); + if(sells.size() == 0) { + return null; + } + PokerSell bestSell = null; + Long weight = null; + for(PokerSell sell: sells) { + List pokers = PokerHelper.clonePokers(selfPoker); + pokers.removeAll(sell.getSellPokers()); + if(pokers.size() == 0) { + return sell; + } + pokersList.set(0, pokers); + AtomicLong counter = new AtomicLong(); + deduce(0, sell, 1, pokersList, counter); + if(weight == null) { + bestSell = sell; + weight = counter.get(); + }else if (counter.get() > weight){ + bestSell = sell; + weight = counter.get(); + } + pokersList.set(0, selfPoker); + } + return bestSell; + } + + private Boolean deduce(int sellCursor, PokerSell lastPokerSell, int cursor, List> pokersList, AtomicLong counter) { + if(cursor > 2) { + cursor = 0; + } + if(sellCursor == cursor) { + lastPokerSell = null; + } + + List original = pokersList.get(cursor); + List sells = PokerHelper.validSells(lastPokerSell, original); + if(sells.size() == 0) { + if(sellCursor != cursor) { + return deduce(sellCursor, lastPokerSell, cursor + 1, pokersList, counter); + } + } + for(PokerSell sell: sells) { + List pokers = PokerHelper.clonePokers(original); + pokers.removeAll(sell.getSellPokers()); + if(pokers.size() == 0) { + return cursor == 0; + }else { + pokersList.set(cursor, pokers); + + Boolean suc = deduce(cursor, sell, cursor + 1, pokersList, counter); + if(cursor != 0) { + pokersList.set(cursor, original); + return suc; + } + if(Math.abs(counter.get()) > DEDUCE_LIMIT) { + pokersList.set(cursor, original); + return counter.get() > DEDUCE_LIMIT; + } + if(suc != null) { + counter.addAndGet((long)(suc ? 1 : -1)); + } + pokersList.set(cursor, original); + } + } + return null; + } + + private static String serialPokers(List pokers){ + if(pokers == null || pokers.size() == 0) { + return "n"; + } + StringBuilder builder = new StringBuilder(); + for(int index = 0; index < pokers.size(); index ++) { + builder.append(pokers.get(index).getLevel().getLevel()).append(index == pokers.size() - 1 ? "" : "_"); + } + return builder.toString(); + } + + private static String serialPokersList(List> pokersList){ + StringBuilder builder = new StringBuilder(); + for(int index = 0; index < pokersList.size(); index ++) { + List pokers = pokersList.get(index); + builder.append(serialPokers(pokers)).append(index == pokersList.size() - 1 ? "" : "m"); + } + return builder.toString(); + } + + @Override + public boolean howToChooseLandlord(List leftPokers, List rightPokers, List myPokers) { + int leftScore = PokerHelper.parsePokerColligationScore(leftPokers); + int rightScore = PokerHelper.parsePokerColligationScore(rightPokers); + int myScore = PokerHelper.parsePokerColligationScore(myPokers); + return myScore >= (leftScore + rightScore) / 2; + } + +} diff --git a/landlords-common/src/main/java/org/nico/ratel/landlords/robot/RobotDecisionMakers.java b/landlords-common/src/main/java/org/nico/ratel/landlords/robot/RobotDecisionMakers.java new file mode 100644 index 0000000..d96d167 --- /dev/null +++ b/landlords-common/src/main/java/org/nico/ratel/landlords/robot/RobotDecisionMakers.java @@ -0,0 +1,37 @@ +package org.nico.ratel.landlords.robot; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.nico.ratel.landlords.entity.ClientSide; +import org.nico.ratel.landlords.entity.Poker; +import org.nico.ratel.landlords.entity.PokerSell; + +/** + * How does the machine decide on a better strategy to win the game + * + * @author nico + */ +public class RobotDecisionMakers { + + private static final Map decisionMakersMap = new HashMap(); + + public static void init() { + decisionMakersMap.put(1, new EasyRobotDecisionMakers()); + decisionMakersMap.put(2, new MediumRobotDecisionMakers()); + } + + public static boolean contains(int difficultyCoefficient) { + return decisionMakersMap.containsKey(difficultyCoefficient); + } + + public static PokerSell howToPlayPokers(int difficultyCoefficient, PokerSell lastPokerSell, ClientSide robot){ + return decisionMakersMap.get(difficultyCoefficient).howToPlayPokers(lastPokerSell, robot); + } + + public static boolean howToChooseLandlord(int difficultyCoefficient, List leftPokers, List rightPokers, List myPokers) { + return decisionMakersMap.get(difficultyCoefficient).howToChooseLandlord(leftPokers, rightPokers, myPokers); + } + +} diff --git a/landlords-common/src/main/java/org/nico/ratel/landlords/transfer/ByteKit.java b/landlords-common/src/main/java/org/nico/ratel/landlords/transfer/ByteKit.java new file mode 100644 index 0000000..df827ad --- /dev/null +++ b/landlords-common/src/main/java/org/nico/ratel/landlords/transfer/ByteKit.java @@ -0,0 +1,60 @@ +package org.nico.ratel.landlords.transfer; + +/** + * Byte manipulation tool + * + * @author nico + */ +public class ByteKit { + + /** + * Target byte array + */ + private byte[] bytes; + + public ByteKit(byte[] bytes) { + this.bytes = bytes; + } + + /** + * Gets the index of the incoming array in the target array, not matched to return -1 + * + * @param bs Incoming array + * @param start Matching start index + * @return Match index, not match to return -1 + */ + public int indexOf(byte[] bs, int start) { + int targetIndex = -1; + if (bs == null) { + return targetIndex; + } + for (int index = start; index < bytes.length; index++) { + byte cbyte = bytes[index]; + if (bs[0] == cbyte) { + boolean isEquals = true; + for (int sindex = 1; sindex < bs.length; sindex++) { + if (index + sindex >= bytes.length || bs[sindex] != bytes[index + sindex]) { + isEquals = false; + break; + } + } + if (isEquals) { + targetIndex = index; + break; + } + } + } + return targetIndex; + } + + /** + * Gets the position of the byte byte in the byte array + * + * @param b Byte + * @param start Matching start index + * @return Match index, not match to return -1 + */ + public int indexOf(byte b, int start) { + return indexOf(new byte[]{b}, start); + } +} diff --git a/landlords-common/src/main/java/org/nico/ratel/landlords/transfer/ByteLink.java b/landlords-common/src/main/java/org/nico/ratel/landlords/transfer/ByteLink.java new file mode 100644 index 0000000..d069672 --- /dev/null +++ b/landlords-common/src/main/java/org/nico/ratel/landlords/transfer/ByteLink.java @@ -0,0 +1,81 @@ +package org.nico.ratel.landlords.transfer; + +public class ByteLink { + + private ByteNode start; + + private ByteNode current; + + private int size; + + public void append(byte b) { + if (start == null) { + start = new ByteNode(b); + current = start; + } else { + ByteNode node = new ByteNode(b); + current.setNext(node); + current = node; + } + size++; + } + + public void append(byte[] bs) { + if (bs != null) { + for (byte b : bs) { + append(b); + } + } + } + + public byte[] toArray() { + if (size == 0) { + return null; + } + byte[] bytes = new byte[size]; + int index = 0; + ByteNode s = start.clone(); + while (s != null) { + bytes[index++] = s.getB(); + s = s.getNext(); + } + return bytes; + } + + public static class ByteNode { + + private byte b; + + private ByteNode next; + + public ByteNode(byte b) { + this.b = b; + } + + public ByteNode(byte b, ByteNode next) { + this.b = b; + this.next = next; + } + + protected ByteNode clone() { + return new ByteNode(b, next); + } + + public byte getB() { + return b; + } + + public void setB(byte b) { + this.b = b; + } + + public ByteNode getNext() { + return next; + } + + public void setNext(ByteNode next) { + this.next = next; + } + + } +} \ No newline at end of file diff --git a/landlords-common/src/main/java/org/nico/ratel/landlords/transfer/TransferProtocolUtils.java b/landlords-common/src/main/java/org/nico/ratel/landlords/transfer/TransferProtocolUtils.java new file mode 100644 index 0000000..ec07a5c --- /dev/null +++ b/landlords-common/src/main/java/org/nico/ratel/landlords/transfer/TransferProtocolUtils.java @@ -0,0 +1,65 @@ +package org.nico.ratel.landlords.transfer; + +import org.nico.noson.Noson; +import org.nico.ratel.landlords.exception.LandlordException; + +/** + * Protocol transport related tools + * + * @author nico + * @time 2018-11-01 20:43 + */ +public class TransferProtocolUtils { + + + /** + * A protocol header that represents the beginning of an available stream of data + */ + public static final byte PROTOCOL_HAED = "#".getBytes()[0]; + + /** + * The end of the protocol used to represent the end of an available stream of data + */ + public static final byte PROTOCOL_TAIL = "$".getBytes()[0]; + + /** + * Serialize the poker list to transportable bytes + * + * @param obj Poker list + * @return Transportable byte array + */ + public static byte[] serialize(Object obj) { + ByteLink bl = new ByteLink(); + bl.append(PROTOCOL_HAED); + bl.append(Noson.reversal(obj).getBytes()); + bl.append(PROTOCOL_TAIL); + return bl.toArray(); + } + + /** + * Deserialize the byte stream as an object + * + * @param bytes Byte array + * @return Genericity + */ + public static T unserialize(byte[] bytes, Class clazz) { + ByteKit bk = new ByteKit(bytes); + int start = -1; + int end = -1; + + int index = bk.indexOf(PROTOCOL_HAED, 0); + if (index != -1) start = index + 1; + + index = bk.indexOf(PROTOCOL_TAIL, 0); + if (index != -1) end = index; + + if (start != -1 && end != -1 && start > end) { + throw new LandlordException("Message format error, head and tail error."); + } else { + byte[] content = new byte[end - start]; + System.arraycopy(bytes, start, content, 0, content.length); + return Noson.convert(new String(content), clazz); + } + } + +} diff --git a/landlords-common/src/main/java/org/nico/ratel/landlords/utils/JsonUtils.java b/landlords-common/src/main/java/org/nico/ratel/landlords/utils/JsonUtils.java new file mode 100644 index 0000000..dd8517c --- /dev/null +++ b/landlords-common/src/main/java/org/nico/ratel/landlords/utils/JsonUtils.java @@ -0,0 +1,17 @@ +package org.nico.ratel.landlords.utils; + +import com.google.gson.Gson; + +public class JsonUtils { + + private static final Gson GSON = new Gson(); + + public static String toJson(Object o){ + return GSON.toJson(o); + } + + public static T fromJson(String json, Class clazz){ + return GSON.fromJson(json, clazz); + } + +} diff --git a/landlords-common/src/main/java/org/nico/ratel/landlords/utils/LastCardsUtils.java b/landlords-common/src/main/java/org/nico/ratel/landlords/utils/LastCardsUtils.java new file mode 100644 index 0000000..8798ed6 --- /dev/null +++ b/landlords-common/src/main/java/org/nico/ratel/landlords/utils/LastCardsUtils.java @@ -0,0 +1,65 @@ +package org.nico.ratel.landlords.utils; + +import org.nico.ratel.landlords.entity.Poker; + +import java.util.*; + +public class LastCardsUtils { + + private static final List defSort = new ArrayList(){{ + add("3"); + add("4"); + add("5"); + add("6"); + add("7"); + add("8"); + add("9"); + add("10"); + add("J"); + add("Q"); + add("K"); + add("A"); + add("2"); + add("S"); + add("X"); + }}; + + public static String getLastCards(List> pokers){ + StringBuffer lastCards = new StringBuffer(); + Map lastCardMap = initLastCards(); + for(int i = 0; i < pokers.size(); i++){ + List pokerList = pokers.get(i); + for(int a = 0; a < pokerList.size(); a++){ + Poker poker = pokerList.get(a); + lastCardMap.put(poker.getLevel().getName(),(lastCardMap.get(poker.getLevel().getName())+1)); + } + } + for(int i = 0; i < defSort.size(); i++){ + String key = defSort.get(i); + lastCards.append(key + "["+lastCardMap.get(key)+"] "); + } + + return lastCards.toString(); + } + + + private static Map initLastCards(){ + Map lastCardMap = new HashMap<>(); + lastCardMap.put("A",0); + lastCardMap.put("2",0); + lastCardMap.put("3",0); + lastCardMap.put("4",0); + lastCardMap.put("5",0); + lastCardMap.put("6",0); + lastCardMap.put("7",0); + lastCardMap.put("8",0); + lastCardMap.put("9",0); + lastCardMap.put("10",0); + lastCardMap.put("J",0); + lastCardMap.put("Q",0); + lastCardMap.put("K",0); + lastCardMap.put("S",0); + lastCardMap.put("X",0); + return lastCardMap; + } +} diff --git a/landlords-common/src/main/java/org/nico/ratel/landlords/utils/ListUtils.java b/landlords-common/src/main/java/org/nico/ratel/landlords/utils/ListUtils.java new file mode 100644 index 0000000..35ae406 --- /dev/null +++ b/landlords-common/src/main/java/org/nico/ratel/landlords/utils/ListUtils.java @@ -0,0 +1,28 @@ +package org.nico.ratel.landlords.utils; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class ListUtils { + + public static List getList(T[] array) { + List list = new ArrayList<>(array.length); + Collections.addAll(list, array); + return list; + } + + public static List getList(List[] array) { + List list = new ArrayList<>(array.length); + for (List t : array) { + list.addAll(t); + } + return list; + } + + public static List getList(List source) { + List list = new ArrayList<>(source.size()); + list.addAll(source); + return list; + } +} diff --git a/landlords-common/src/main/java/org/nico/ratel/landlords/utils/OptionsUtils.java b/landlords-common/src/main/java/org/nico/ratel/landlords/utils/OptionsUtils.java new file mode 100644 index 0000000..20fc172 --- /dev/null +++ b/landlords-common/src/main/java/org/nico/ratel/landlords/utils/OptionsUtils.java @@ -0,0 +1,12 @@ +package org.nico.ratel.landlords.utils; + +public class OptionsUtils { + + public static int getOptions(String line) { + int option = -1; + try { + option = Integer.parseInt(line); + } catch (Exception ignored) {} + return option; + } +} diff --git a/landlords-common/src/main/java/org/nico/ratel/landlords/utils/RegxUtils.java b/landlords-common/src/main/java/org/nico/ratel/landlords/utils/RegxUtils.java new file mode 100644 index 0000000..88aed6a --- /dev/null +++ b/landlords-common/src/main/java/org/nico/ratel/landlords/utils/RegxUtils.java @@ -0,0 +1,10 @@ +package org.nico.ratel.landlords.utils; + +public class RegxUtils { + +// private final static String POKER_SELECT_REGX = "^[2-9]" + +// public static isRegularPokerSelect(String line) { +// 123456789t +// } +} diff --git a/landlords-common/src/main/java/org/nico/ratel/landlords/utils/StreamUtils.java b/landlords-common/src/main/java/org/nico/ratel/landlords/utils/StreamUtils.java new file mode 100644 index 0000000..a389a3b --- /dev/null +++ b/landlords-common/src/main/java/org/nico/ratel/landlords/utils/StreamUtils.java @@ -0,0 +1,48 @@ +package org.nico.ratel.landlords.utils; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.URL; +import java.net.URLConnection; + +public class StreamUtils { + + /** + * Convert input stream to string + * + * @param inStream Input stream + * @return {@link String} + */ + public static String convertToString(InputStream inStream) { + BufferedReader br = new BufferedReader(new InputStreamReader(inStream)); + StringBuilder reqStr = new StringBuilder(); + char[] buf = new char[2048]; + int len; + try { + while ((len = br.read(buf)) != -1) { + reqStr.append(new String(buf, 0, len)); + } + br.close(); + } catch (IOException e) { + return null; + } finally { + try { + br.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + return reqStr.toString(); + } + + public static String convertToString(URL url) throws IOException { + URLConnection con = url.openConnection(); + con.setUseCaches(false); + con.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.193 Safari/537.36"); + return convertToString(con.getInputStream()); + } + + +} diff --git a/landlords-common/src/test/java/org/nico/ratel/landlords/helper/tests/PokerHelperTest.java b/landlords-common/src/test/java/org/nico/ratel/landlords/helper/tests/PokerHelperTest.java new file mode 100644 index 0000000..f84b3fc --- /dev/null +++ b/landlords-common/src/test/java/org/nico/ratel/landlords/helper/tests/PokerHelperTest.java @@ -0,0 +1,243 @@ +package org.nico.ratel.landlords.helper.tests; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.nico.ratel.landlords.entity.Poker; +import org.nico.ratel.landlords.entity.PokerSell; +import org.nico.ratel.landlords.enums.PokerLevel; +import org.nico.ratel.landlords.enums.PokerType; +import org.nico.ratel.landlords.enums.SellType; +import org.nico.ratel.landlords.helper.PokerHelper; + +import java.util.ArrayList; + +public class PokerHelperTest { + + private ArrayList pokers = new ArrayList<>(); + + @Before + public void setUp() { + pokers.add(new Poker(PokerLevel.LEVEL_3, PokerType.BLANK)); + pokers.add(new Poker(PokerLevel.LEVEL_4, PokerType.DIAMOND)); + pokers.add(new Poker(PokerLevel.LEVEL_4, PokerType.DIAMOND)); + pokers.add(new Poker(PokerLevel.LEVEL_5, PokerType.CLUB)); + pokers.add(new Poker(PokerLevel.LEVEL_5, PokerType.CLUB)); + pokers.add(new Poker(PokerLevel.LEVEL_5, PokerType.CLUB)); + pokers.add(new Poker(PokerLevel.LEVEL_7, PokerType.SPADE)); + pokers.add(new Poker(PokerLevel.LEVEL_7, PokerType.HEART)); + pokers.add(new Poker(PokerLevel.LEVEL_7, PokerType.HEART)); + pokers.add(new Poker(PokerLevel.LEVEL_7, PokerType.HEART)); + } + + @Test + public void testComparePoker() { + Assert.assertTrue(PokerHelper.comparePoker(new ArrayList<>(), new ArrayList<>())); + } + + @Test + public void testCheckPokerIndex() { + Assert.assertFalse(PokerHelper.checkPokerIndex(new int[]{}, new ArrayList<>())); + Assert.assertFalse(PokerHelper.checkPokerIndex(new int[]{2, -4_194_302}, new ArrayList<>())); + } + + @Test + public void testGetIndexes() { + Assert.assertNull(PokerHelper.getIndexes(new Character[]{'3', '4', '5', '6', '7', '8'}, pokers)); + Assert.assertNotNull(PokerHelper.getIndexes(new Character[]{}, new ArrayList<>())); + Assert.assertEquals(0, PokerHelper.getIndexes(new Character[]{}, new ArrayList<>()).length); + } + + @Test + public void testGetPoker() { + Assert.assertEquals(PokerLevel.LEVEL_3, PokerHelper.getPoker(new int[]{1, 2}, pokers).get(0).getLevel()); + Assert.assertEquals(PokerType.BLANK, PokerHelper.getPoker(new int[]{1, 2}, pokers).get(0).getType()); + Assert.assertEquals(PokerLevel.LEVEL_4, PokerHelper.getPoker(new int[]{1, 2}, pokers).get(1).getLevel()); + Assert.assertEquals(PokerType.DIAMOND, PokerHelper.getPoker(new int[]{1, 2}, pokers).get(1).getType()); + } + + @Test + public void testPrintPoker() { + Assert.assertNotNull(PokerHelper.printPoker(pokers)); + } + + @Test + public void testDistributePoker() { + Assert.assertNotNull(PokerHelper.distributePoker()); + } + + @Test + public void testCheckPokerType1() { + pokers.clear(); + Assert.assertNull(PokerHelper.checkPokerType(pokers).getSellPokers()); + Assert.assertEquals(-1, PokerHelper.checkPokerType(pokers).getScore()); + Assert.assertEquals(SellType.ILLEGAL, PokerHelper.checkPokerType(pokers).getSellType()); + + pokers.add(new Poker(PokerLevel.LEVEL_SMALL_KING, PokerType.BLANK)); + pokers.add(new Poker(PokerLevel.LEVEL_BIG_KING, PokerType.DIAMOND)); + Assert.assertEquals(pokers, PokerHelper.checkPokerType(pokers).getSellPokers()); + Assert.assertEquals(2147483647, PokerHelper.checkPokerType(pokers).getScore()); + Assert.assertEquals(SellType.KING_BOMB, PokerHelper.checkPokerType(pokers).getSellType()); + } + + @Test + public void testCheckPokerType2() { + pokers.clear(); + pokers.add(new Poker(PokerLevel.LEVEL_7, PokerType.HEART)); + Assert.assertEquals(pokers, PokerHelper.checkPokerType(pokers).getSellPokers()); + Assert.assertEquals(7, PokerHelper.checkPokerType(pokers).getScore()); + Assert.assertEquals(SellType.SINGLE, PokerHelper.checkPokerType(pokers).getSellType()); + + pokers.add(new Poker(PokerLevel.LEVEL_7, PokerType.HEART)); + Assert.assertEquals(pokers, PokerHelper.checkPokerType(pokers).getSellPokers()); + Assert.assertEquals(7, PokerHelper.checkPokerType(pokers).getScore()); + Assert.assertEquals(SellType.DOUBLE, PokerHelper.checkPokerType(pokers).getSellType()); + + pokers.add(new Poker(PokerLevel.LEVEL_7, PokerType.HEART)); + Assert.assertEquals(pokers, PokerHelper.checkPokerType(pokers).getSellPokers()); + Assert.assertEquals(7, PokerHelper.checkPokerType(pokers).getScore()); + Assert.assertEquals(SellType.THREE, PokerHelper.checkPokerType(pokers).getSellType()); + + pokers.add(new Poker(PokerLevel.LEVEL_7, PokerType.HEART)); + Assert.assertEquals(pokers, PokerHelper.checkPokerType(pokers).getSellPokers()); + Assert.assertEquals(1027, PokerHelper.checkPokerType(pokers).getScore()); + Assert.assertEquals(SellType.BOMB, PokerHelper.checkPokerType(pokers).getSellType()); + + pokers.remove(pokers.size() - 1); + pokers.add(new Poker(PokerLevel.LEVEL_8, PokerType.BLANK)); + Assert.assertEquals(pokers, PokerHelper.checkPokerType(pokers).getSellPokers()); + Assert.assertEquals(7, PokerHelper.checkPokerType(pokers).getScore()); + Assert.assertEquals(SellType.THREE_ZONES_SINGLE, PokerHelper.checkPokerType(pokers).getSellType()); + + pokers.add(new Poker(PokerLevel.LEVEL_8, PokerType.BLANK)); + Assert.assertEquals(pokers, PokerHelper.checkPokerType(pokers).getSellPokers()); + Assert.assertEquals(7, PokerHelper.checkPokerType(pokers).getScore()); + Assert.assertEquals(SellType.THREE_ZONES_DOUBLE, PokerHelper.checkPokerType(pokers).getSellType()); + + pokers.add(new Poker(PokerLevel.LEVEL_8, PokerType.BLANK)); + pokers.add(new Poker(PokerLevel.LEVEL_9, PokerType.BLANK)); + pokers.add(new Poker(PokerLevel.LEVEL_10, PokerType.BLANK)); + Assert.assertEquals(pokers, PokerHelper.checkPokerType(pokers).getSellPokers()); + Assert.assertEquals(8, PokerHelper.checkPokerType(pokers).getScore()); + Assert.assertEquals(SellType.THREE_STRAIGHT_WITH_SINGLE, PokerHelper.checkPokerType(pokers).getSellType()); + + pokers.add(new Poker(PokerLevel.LEVEL_9, PokerType.BLANK)); + pokers.add(new Poker(PokerLevel.LEVEL_10, PokerType.BLANK)); + Assert.assertEquals(pokers, PokerHelper.checkPokerType(pokers).getSellPokers()); + Assert.assertEquals(8, PokerHelper.checkPokerType(pokers).getScore()); + Assert.assertEquals(SellType.THREE_STRAIGHT_WITH_DOUBLE, PokerHelper.checkPokerType(pokers).getSellType()); + } + + @Test + public void testCheckPokerType3() { + pokers.clear(); + pokers.add(new Poker(PokerLevel.LEVEL_6, PokerType.HEART)); + pokers.add(new Poker(PokerLevel.LEVEL_7, PokerType.HEART)); + pokers.add(new Poker(PokerLevel.LEVEL_8, PokerType.HEART)); + pokers.add(new Poker(PokerLevel.LEVEL_9, PokerType.BLANK)); + pokers.add(new Poker(PokerLevel.LEVEL_10, PokerType.BLANK)); + Assert.assertEquals(pokers, PokerHelper.checkPokerType(pokers).getSellPokers()); + Assert.assertEquals(10, PokerHelper.checkPokerType(pokers).getScore()); + Assert.assertEquals(SellType.SINGLE_STRAIGHT, PokerHelper.checkPokerType(pokers).getSellType()); + + pokers.add(new Poker(PokerLevel.LEVEL_6, PokerType.HEART)); + pokers.add(new Poker(PokerLevel.LEVEL_7, PokerType.HEART)); + pokers.add(new Poker(PokerLevel.LEVEL_8, PokerType.HEART)); + pokers.add(new Poker(PokerLevel.LEVEL_9, PokerType.BLANK)); + pokers.add(new Poker(PokerLevel.LEVEL_10, PokerType.BLANK)); + Assert.assertEquals(pokers, PokerHelper.checkPokerType(pokers).getSellPokers()); + Assert.assertEquals(10, PokerHelper.checkPokerType(pokers).getScore()); + Assert.assertEquals(SellType.DOUBLE_STRAIGHT, PokerHelper.checkPokerType(pokers).getSellType()); + + pokers.add(new Poker(PokerLevel.LEVEL_6, PokerType.HEART)); + pokers.add(new Poker(PokerLevel.LEVEL_7, PokerType.HEART)); + pokers.add(new Poker(PokerLevel.LEVEL_8, PokerType.HEART)); + pokers.add(new Poker(PokerLevel.LEVEL_9, PokerType.BLANK)); + pokers.add(new Poker(PokerLevel.LEVEL_10, PokerType.BLANK)); + Assert.assertEquals(pokers, PokerHelper.checkPokerType(pokers).getSellPokers()); + Assert.assertEquals(10, PokerHelper.checkPokerType(pokers).getScore()); + Assert.assertEquals(SellType.THREE_STRAIGHT, PokerHelper.checkPokerType(pokers).getSellType()); + + pokers.add(new Poker(PokerLevel.LEVEL_6, PokerType.HEART)); + pokers.add(new Poker(PokerLevel.LEVEL_7, PokerType.HEART)); + pokers.add(new Poker(PokerLevel.LEVEL_8, PokerType.HEART)); + pokers.add(new Poker(PokerLevel.LEVEL_9, PokerType.BLANK)); + pokers.add(new Poker(PokerLevel.LEVEL_10, PokerType.BLANK)); + Assert.assertEquals(pokers, PokerHelper.checkPokerType(pokers).getSellPokers()); + Assert.assertEquals(10, PokerHelper.checkPokerType(pokers).getScore()); + Assert.assertEquals(SellType.FOUR_STRAIGHT, PokerHelper.checkPokerType(pokers).getSellType()); + } + + @Test + public void testCheckPokerType4() { + pokers.clear(); + pokers.add(new Poker(PokerLevel.LEVEL_8, PokerType.HEART)); + pokers.add(new Poker(PokerLevel.LEVEL_8, PokerType.HEART)); + pokers.add(new Poker(PokerLevel.LEVEL_8, PokerType.HEART)); + pokers.add(new Poker(PokerLevel.LEVEL_8, PokerType.HEART)); + pokers.add(new Poker(PokerLevel.LEVEL_9, PokerType.BLANK)); + pokers.add(new Poker(PokerLevel.LEVEL_10, PokerType.BLANK)); + Assert.assertEquals(pokers, PokerHelper.checkPokerType(pokers).getSellPokers()); + Assert.assertEquals(8, PokerHelper.checkPokerType(pokers).getScore()); + Assert.assertEquals(SellType.FOUR_ZONES_SINGLE, PokerHelper.checkPokerType(pokers).getSellType()); + + pokers.add(new Poker(PokerLevel.LEVEL_5, PokerType.HEART)); + pokers.add(new Poker(PokerLevel.LEVEL_6, PokerType.HEART)); + pokers.add(new Poker(PokerLevel.LEVEL_7, PokerType.HEART)); + pokers.add(new Poker(PokerLevel.LEVEL_7, PokerType.HEART)); + pokers.add(new Poker(PokerLevel.LEVEL_7, PokerType.HEART)); + pokers.add(new Poker(PokerLevel.LEVEL_7, PokerType.HEART)); + Assert.assertEquals(pokers, PokerHelper.checkPokerType(pokers).getSellPokers()); + Assert.assertEquals(8, PokerHelper.checkPokerType(pokers).getScore()); + Assert.assertEquals(SellType.FOUR_STRAIGHT_WITH_SINGLE, PokerHelper.checkPokerType(pokers).getSellType()); + } + + @Test + public void testCheckPokerType5() { + pokers.clear(); + pokers.add(new Poker(PokerLevel.LEVEL_8, PokerType.HEART)); + pokers.add(new Poker(PokerLevel.LEVEL_8, PokerType.HEART)); + pokers.add(new Poker(PokerLevel.LEVEL_8, PokerType.HEART)); + pokers.add(new Poker(PokerLevel.LEVEL_8, PokerType.HEART)); + pokers.add(new Poker(PokerLevel.LEVEL_9, PokerType.BLANK)); + pokers.add(new Poker(PokerLevel.LEVEL_9, PokerType.BLANK)); + pokers.add(new Poker(PokerLevel.LEVEL_10, PokerType.BLANK)); + pokers.add(new Poker(PokerLevel.LEVEL_10, PokerType.BLANK)); + Assert.assertEquals(pokers, PokerHelper.checkPokerType(pokers).getSellPokers()); + Assert.assertEquals(8, PokerHelper.checkPokerType(pokers).getScore()); + Assert.assertEquals(SellType.FOUR_ZONES_DOUBLE, PokerHelper.checkPokerType(pokers).getSellType()); + + pokers.add(new Poker(PokerLevel.LEVEL_5, PokerType.HEART)); + pokers.add(new Poker(PokerLevel.LEVEL_5, PokerType.HEART)); + pokers.add(new Poker(PokerLevel.LEVEL_6, PokerType.HEART)); + pokers.add(new Poker(PokerLevel.LEVEL_6, PokerType.HEART)); + pokers.add(new Poker(PokerLevel.LEVEL_7, PokerType.HEART)); + pokers.add(new Poker(PokerLevel.LEVEL_7, PokerType.HEART)); + pokers.add(new Poker(PokerLevel.LEVEL_7, PokerType.HEART)); + pokers.add(new Poker(PokerLevel.LEVEL_7, PokerType.HEART)); + Assert.assertEquals(pokers, PokerHelper.checkPokerType(pokers).getSellPokers()); + Assert.assertEquals(8, PokerHelper.checkPokerType(pokers).getScore()); + Assert.assertEquals(SellType.FOUR_STRAIGHT_WITH_DOUBLE, PokerHelper.checkPokerType(pokers).getSellType()); + } + + @Test + public void testCheckPokerType6() { + pokers.clear(); + pokers.add(new Poker(PokerLevel.LEVEL_6, PokerType.HEART)); + pokers.add(new Poker(PokerLevel.LEVEL_6, PokerType.HEART)); + pokers.add(new Poker(PokerLevel.LEVEL_6, PokerType.HEART)); + pokers.add(new Poker(PokerLevel.LEVEL_7, PokerType.BLANK)); + pokers.add(new Poker(PokerLevel.LEVEL_7, PokerType.BLANK)); + pokers.add(new Poker(PokerLevel.LEVEL_7, PokerType.BLANK)); + pokers.add(new Poker(PokerLevel.LEVEL_8, PokerType.BLANK)); + pokers.add(new Poker(PokerLevel.LEVEL_8, PokerType.BLANK)); + pokers.add(new Poker(PokerLevel.LEVEL_8, PokerType.BLANK)); + pokers.add(new Poker(PokerLevel.LEVEL_4, PokerType.BLANK)); + pokers.add(new Poker(PokerLevel.LEVEL_4, PokerType.BLANK)); + pokers.add(new Poker(PokerLevel.LEVEL_5, PokerType.BLANK)); + PokerSell pokerSell = PokerHelper.checkPokerType(pokers); + Assert.assertEquals(pokers, pokerSell.getSellPokers()); + Assert.assertEquals(8, PokerHelper.checkPokerType(pokers).getScore()); + Assert.assertEquals(SellType.THREE_STRAIGHT_WITH_SINGLE, pokerSell.getSellType()); + } +} diff --git a/landlords-common/src/test/java/org/nico/ratel/landlords/robot/tests/MediumRobotDecisionMakersTests.java b/landlords-common/src/test/java/org/nico/ratel/landlords/robot/tests/MediumRobotDecisionMakersTests.java new file mode 100644 index 0000000..0a319ec --- /dev/null +++ b/landlords-common/src/test/java/org/nico/ratel/landlords/robot/tests/MediumRobotDecisionMakersTests.java @@ -0,0 +1,63 @@ +package org.nico.ratel.landlords.robot.tests; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.Test; +import org.nico.ratel.landlords.entity.ClientSide; +import org.nico.ratel.landlords.entity.Poker; +import org.nico.ratel.landlords.entity.PokerSell; +import org.nico.ratel.landlords.enums.PokerLevel; +import org.nico.ratel.landlords.enums.PokerType; +import org.nico.ratel.landlords.enums.SellType; +import org.nico.ratel.landlords.helper.PokerHelper; +import org.nico.ratel.landlords.robot.MediumRobotDecisionMakers; + +public class MediumRobotDecisionMakersTests { + + private List buildPokers(Object[] values){ + List pokers = new ArrayList(); + for(Object v: values) { + if(v == null){ + continue; + } + if(v instanceof String) { + pokers.add(new Poker(PokerLevel.parseByName((String)v), PokerType.CLUB)); + }else if(v instanceof Integer || v.getClass() == int.class) { + pokers.add(new Poker(PokerLevel.parseByLevel((int)v), PokerType.CLUB)); + } + } + return pokers; + } + + @Test + public void testMedium_1() { + ClientSide self = new ClientSide(); + ClientSide right = new ClientSide(); + ClientSide left = new ClientSide(); + self.setPre(left); + self.setNext(right); + left.setPre(right); + left.setNext(self); + right.setPre(self); + right.setNext(left); + self.setPokers(buildPokers(new Object[] {3,3,3,4,4,4,5,6,8,8,11,12,13,13,14,15,15})); + right.setPokers(buildPokers(new Object[] {3,4,5,6,7,9,9,11,11,12,12,12,14,16})); + left.setPokers(buildPokers(new Object[] {6,6,7,7,7,8,8,9,9,10,10,10,10,11,13,14,14,17})); + +// self.setPokers(buildPokers(new Object[] {9,9,3,4})); +// right.setPokers(buildPokers(new Object[] {3,3,9,9,10})); +// left.setPokers(buildPokers(new Object[] {6,6,8,8})); + + MediumRobotDecisionMakers mediumRobot = new MediumRobotDecisionMakers(); + + PokerSell lastSell = PokerHelper.checkPokerType(buildPokers(new Object[] {5,5})); + PokerSell sell = mediumRobot.howToPlayPokers(lastSell, self); + if(sell == null) { + System.out.println("打不起"); + }else { + System.out.println(PokerHelper.printPoker(sell.getSellPokers())); + } + + } +} diff --git a/landlords-server/pom.xml b/landlords-server/pom.xml new file mode 100644 index 0000000..03af6af --- /dev/null +++ b/landlords-server/pom.xml @@ -0,0 +1,59 @@ + + 4.0.0 + landlords-server + landlords-server + This is a console version of the fight landlord game + + + com.smallnico.ratel + landlords + 1.4.0 + + + + org.nico.ratel.landlords.server.SimpleServer + + + + + com.smallnico.ratel + landlords-common + 1.4.0 + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + ${start-class} + + + + + repackage + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 1.8 + 1.8 + + -parameters + + true + + + + + + \ No newline at end of file diff --git a/landlords-server/src/main/java/org/nico/ratel/landlords/server/ServerContains.java b/landlords-server/src/main/java/org/nico/ratel/landlords/server/ServerContains.java new file mode 100644 index 0000000..5b8191b --- /dev/null +++ b/landlords-server/src/main/java/org/nico/ratel/landlords/server/ServerContains.java @@ -0,0 +1,73 @@ +package org.nico.ratel.landlords.server; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentSkipListMap; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +import org.nico.ratel.landlords.entity.ClientSide; +import org.nico.ratel.landlords.entity.Room; + +public class ServerContains { + + /** + * Server port + */ + public static int port = 1024; + + /** + * The map of server side + */ + private final static Map ROOM_MAP = new ConcurrentSkipListMap<>(); + + /** + * The list of client side + */ + public final static Map CLIENT_SIDE_MAP = new ConcurrentSkipListMap<>(); + + public final static Map CHANNEL_ID_MAP = new ConcurrentHashMap<>(); + + private final static AtomicInteger CLIENT_ATOMIC_ID = new AtomicInteger(1); + + private final static AtomicInteger SERVER_ATOMIC_ID = new AtomicInteger(1); + + public final static int getClientId() { + return CLIENT_ATOMIC_ID.getAndIncrement(); + } + + public final static int getServerId() { + return SERVER_ATOMIC_ID.getAndIncrement(); + } + + public final static ThreadPoolExecutor THREAD_EXCUTER = new ThreadPoolExecutor(500, 500, 0, TimeUnit.MILLISECONDS, + new LinkedBlockingQueue()); + + /** + * Get room by id, with flush time + * + * @param id room id + * @return + */ + public static Room getRoom(int id) { + Room room = ROOM_MAP.get(id); + if (room != null) { + room.setLastFlushTime(System.currentTimeMillis()); + } + return room; + } + + public static Map getRoomMap() { + return ROOM_MAP; + } + + public static Room removeRoom(int id) { + return ROOM_MAP.remove(id); + } + + public static Room addRoom(Room room) { + return ROOM_MAP.put(room.getId(), room); + } +} diff --git a/landlords-server/src/main/java/org/nico/ratel/landlords/server/SimpleServer.java b/landlords-server/src/main/java/org/nico/ratel/landlords/server/SimpleServer.java new file mode 100644 index 0000000..7b41e21 --- /dev/null +++ b/landlords-server/src/main/java/org/nico/ratel/landlords/server/SimpleServer.java @@ -0,0 +1,24 @@ +package org.nico.ratel.landlords.server; + +import org.nico.ratel.landlords.server.proxy.ProtobufProxy; +import org.nico.ratel.landlords.server.proxy.WebsocketProxy; + +public class SimpleServer { + + public static void main(String[] args) throws InterruptedException { + if (args != null && args.length > 1) { + if (args[0].equalsIgnoreCase("-p") || args[0].equalsIgnoreCase("-port")) { + ServerContains.port = Integer.parseInt(args[1]); + } + } + new Thread(() -> { + try { + new ProtobufProxy().start(ServerContains.port); + } catch (InterruptedException e) { + e.printStackTrace(); + } + }).start(); + new WebsocketProxy().start(ServerContains.port + 1); + + } +} diff --git a/landlords-server/src/main/java/org/nico/ratel/landlords/server/event/ServerEventListener.java b/landlords-server/src/main/java/org/nico/ratel/landlords/server/event/ServerEventListener.java new file mode 100644 index 0000000..8892b28 --- /dev/null +++ b/landlords-server/src/main/java/org/nico/ratel/landlords/server/event/ServerEventListener.java @@ -0,0 +1,41 @@ +package org.nico.ratel.landlords.server.event; + +import java.lang.reflect.InvocationTargetException; +import java.util.HashMap; +import java.util.Map; + +import org.nico.ratel.landlords.entity.ClientSide; +import org.nico.ratel.landlords.enums.ServerEventCode; + +public interface ServerEventListener { + + void call(ClientSide client, String data); + + Map LISTENER_MAP = new HashMap<>(); + + String LISTENER_PREFIX = "org.nico.ratel.landlords.server.event.ServerEventListener_"; + + @SuppressWarnings("unchecked") + static ServerEventListener get(ServerEventCode code) { + ServerEventListener listener = null; + try { + if (ServerEventListener.LISTENER_MAP.containsKey(code)) { + listener = ServerEventListener.LISTENER_MAP.get(code); + } else { + String eventListener = LISTENER_PREFIX + code.name(); + Class listenerClass = (Class) Class.forName(eventListener); + try { + listener = listenerClass.getDeclaredConstructor().newInstance(); + } catch (InvocationTargetException | NoSuchMethodException e) { + e.printStackTrace(); + } + ServerEventListener.LISTENER_MAP.put(code, listener); + } + return listener; + } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) { + e.printStackTrace(); + } + return null; + } + +} diff --git a/landlords-server/src/main/java/org/nico/ratel/landlords/server/event/ServerEventListener_CODE_CLIENT_EXIT.java b/landlords-server/src/main/java/org/nico/ratel/landlords/server/event/ServerEventListener_CODE_CLIENT_EXIT.java new file mode 100644 index 0000000..71f25d1 --- /dev/null +++ b/landlords-server/src/main/java/org/nico/ratel/landlords/server/event/ServerEventListener_CODE_CLIENT_EXIT.java @@ -0,0 +1,50 @@ +package org.nico.ratel.landlords.server.event; + +import org.nico.ratel.landlords.channel.ChannelUtils; +import org.nico.ratel.landlords.entity.ClientSide; +import org.nico.ratel.landlords.entity.Room; +import org.nico.ratel.landlords.enums.ClientEventCode; +import org.nico.ratel.landlords.enums.ClientRole; +import org.nico.ratel.landlords.helper.MapHelper; +import org.nico.ratel.landlords.server.ServerContains; + +public class ServerEventListener_CODE_CLIENT_EXIT implements ServerEventListener { + + private static final Object locked = new Object(); + + @Override + public void call(ClientSide clientSide, String data) { + synchronized (locked){ + Room room = ServerContains.getRoom(clientSide.getRoomId()); + if (room == null) { + return; + } + String result = MapHelper.newInstance() + .put("roomId", room.getId()) + .put("exitClientId", clientSide.getId()) + .put("exitClientNickname", clientSide.getNickname()) + .json(); + for (ClientSide client : room.getClientSideList()) { + if (client.getRole() == ClientRole.PLAYER) { + ChannelUtils.pushToClient(client.getChannel(), ClientEventCode.CODE_CLIENT_EXIT, result); + client.init(); + } + } + + notifyWatcherClientExit(room, clientSide); + ServerContains.removeRoom(room.getId()); + } + } + + /** + * 通知所有观战者玩家退出游戏 + * + * @param room 房间 + * @param player 退出游戏玩家 + */ + private void notifyWatcherClientExit(Room room, ClientSide player) { + for (ClientSide watcher : room.getWatcherList()) { + ChannelUtils.pushToClient(watcher.getChannel(), ClientEventCode.CODE_CLIENT_EXIT, player.getNickname()); + } + } +} diff --git a/landlords-server/src/main/java/org/nico/ratel/landlords/server/event/ServerEventListener_CODE_CLIENT_INFO_SET.java b/landlords-server/src/main/java/org/nico/ratel/landlords/server/event/ServerEventListener_CODE_CLIENT_INFO_SET.java new file mode 100644 index 0000000..4735a36 --- /dev/null +++ b/landlords-server/src/main/java/org/nico/ratel/landlords/server/event/ServerEventListener_CODE_CLIENT_INFO_SET.java @@ -0,0 +1,22 @@ +package org.nico.ratel.landlords.server.event; + +import org.nico.ratel.landlords.entity.ClientSide; +import org.nico.ratel.landlords.utils.JsonUtils; + +import java.util.Map; + +public class ServerEventListener_CODE_CLIENT_INFO_SET implements ServerEventListener { + + private static final String DEFAULT_VERSION = "v1.2.8"; + + @Override + public void call(ClientSide client, String info) { + Map infos = JsonUtils.fromJson(info, Map.class); + // Get client version + client.setVersion(DEFAULT_VERSION); + if (infos.containsKey("version")){ + client.setVersion(String.valueOf(infos.get("version"))); + } + } + +} diff --git a/landlords-server/src/main/java/org/nico/ratel/landlords/server/event/ServerEventListener_CODE_CLIENT_NICKNAME_SET.java b/landlords-server/src/main/java/org/nico/ratel/landlords/server/event/ServerEventListener_CODE_CLIENT_NICKNAME_SET.java new file mode 100644 index 0000000..844acda --- /dev/null +++ b/landlords-server/src/main/java/org/nico/ratel/landlords/server/event/ServerEventListener_CODE_CLIENT_NICKNAME_SET.java @@ -0,0 +1,24 @@ +package org.nico.ratel.landlords.server.event; + +import org.nico.ratel.landlords.channel.ChannelUtils; +import org.nico.ratel.landlords.entity.ClientSide; +import org.nico.ratel.landlords.enums.ClientEventCode; +import org.nico.ratel.landlords.helper.MapHelper; +import org.nico.ratel.landlords.server.ServerContains; + +public class ServerEventListener_CODE_CLIENT_NICKNAME_SET implements ServerEventListener { + + public static final int NICKNAME_MAX_LENGTH = 10; + + @Override + public void call(ClientSide client, String nickname) { + if (nickname.trim().length() > NICKNAME_MAX_LENGTH || nickname.trim().isEmpty()) { + String result = MapHelper.newInstance().put("invalidLength", nickname.trim().length()).json(); + ChannelUtils.pushToClient(client.getChannel(), ClientEventCode.CODE_CLIENT_NICKNAME_SET, result); + return; + } + ServerContains.CLIENT_SIDE_MAP.get(client.getId()).setNickname(nickname); + ChannelUtils.pushToClient(client.getChannel(), ClientEventCode.CODE_SHOW_OPTIONS, null); + } + +} diff --git a/landlords-server/src/main/java/org/nico/ratel/landlords/server/event/ServerEventListener_CODE_CLIENT_OFFLINE.java b/landlords-server/src/main/java/org/nico/ratel/landlords/server/event/ServerEventListener_CODE_CLIENT_OFFLINE.java new file mode 100644 index 0000000..d17ac5b --- /dev/null +++ b/landlords-server/src/main/java/org/nico/ratel/landlords/server/event/ServerEventListener_CODE_CLIENT_OFFLINE.java @@ -0,0 +1,39 @@ +package org.nico.ratel.landlords.server.event; + +import org.nico.ratel.landlords.channel.ChannelUtils; +import org.nico.ratel.landlords.entity.ClientSide; +import org.nico.ratel.landlords.entity.Room; +import org.nico.ratel.landlords.enums.ClientEventCode; +import org.nico.ratel.landlords.enums.ClientRole; +import org.nico.ratel.landlords.helper.MapHelper; +import org.nico.ratel.landlords.server.ServerContains; + +public class ServerEventListener_CODE_CLIENT_OFFLINE implements ServerEventListener { + + @Override + public void call(ClientSide clientSide, String data) { + + Room room = ServerContains.getRoom(clientSide.getRoomId()); + + if (room == null) { + ServerContains.CLIENT_SIDE_MAP.remove(clientSide.getId()); + return; + } + + String result = MapHelper.newInstance() + .put("roomId", room.getId()) + .put("exitClientId", clientSide.getId()) + .put("exitClientNickname", clientSide.getNickname()) + .json(); + for (ClientSide client : room.getClientSideList()) { + if (client.getRole() != ClientRole.PLAYER) { + continue; + } + if (client.getId() != clientSide.getId()) { + ChannelUtils.pushToClient(client.getChannel(), ClientEventCode.CODE_CLIENT_EXIT, result); + client.init(); + } + } + ServerContains.removeRoom(room.getId()); + } +} diff --git a/landlords-server/src/main/java/org/nico/ratel/landlords/server/event/ServerEventListener_CODE_GAME_LANDLORD_ELECT.java b/landlords-server/src/main/java/org/nico/ratel/landlords/server/event/ServerEventListener_CODE_GAME_LANDLORD_ELECT.java new file mode 100644 index 0000000..d33141f --- /dev/null +++ b/landlords-server/src/main/java/org/nico/ratel/landlords/server/event/ServerEventListener_CODE_GAME_LANDLORD_ELECT.java @@ -0,0 +1,124 @@ +package org.nico.ratel.landlords.server.event; + + +import org.nico.ratel.landlords.channel.ChannelUtils; +import org.nico.ratel.landlords.entity.ClientSide; +import org.nico.ratel.landlords.entity.Room; +import org.nico.ratel.landlords.enums.ClientEventCode; +import org.nico.ratel.landlords.enums.ClientRole; +import org.nico.ratel.landlords.enums.ClientType; +import org.nico.ratel.landlords.enums.ServerEventCode; +import org.nico.ratel.landlords.helper.MapHelper; +import org.nico.ratel.landlords.helper.PokerHelper; +import org.nico.ratel.landlords.server.ServerContains; +import org.nico.ratel.landlords.server.robot.RobotEventListener; + +import java.util.Map; + +public class ServerEventListener_CODE_GAME_LANDLORD_ELECT implements ServerEventListener { + + @Override + public void call(ClientSide clientSide, String data) { + + Room room = ServerContains.getRoom(clientSide.getRoomId()); + + if (room == null) { + return; + } + if (Boolean.parseBoolean(data)) { + confirmLandlord(clientSide, room); + return; + } + if (clientSide.getNext().getId() == room.getFirstSellClient()) { + for (ClientSide client : room.getClientSideList()) { + if (client.getRole() == ClientRole.PLAYER) { + ChannelUtils.pushToClient(client.getChannel(), ClientEventCode.CODE_GAME_LANDLORD_CYCLE, null); + } + } + ServerEventListener.get(ServerEventCode.CODE_GAME_STARTING).call(clientSide, null); + return; + } + ClientSide turnClientSide = clientSide.getNext(); + room.setCurrentSellClient(turnClientSide.getId()); + String result = MapHelper.newInstance() + .put("roomId", room.getId()) + .put("roomOwner", room.getRoomOwner()) + .put("roomClientCount", room.getClientSideList().size()) + .put("preClientNickname", clientSide.getNickname()) + .put("nextClientNickname", turnClientSide.getNickname()) + .put("nextClientId", turnClientSide.getId()) + .json(); + + for (ClientSide client : room.getClientSideList()) { + if (client.getRole() == ClientRole.PLAYER) { + ChannelUtils.pushToClient(client.getChannel(), ClientEventCode.CODE_GAME_LANDLORD_ELECT, result); + continue; + } + if (client.getId() == turnClientSide.getId()) { + RobotEventListener.get(ClientEventCode.CODE_GAME_LANDLORD_ELECT).call(client, result); + } + } + notifyWatcherRobLandlord(room, clientSide); + } + + public void confirmLandlord(ClientSide clientSide, Room room) { + clientSide.getPokers().addAll(room.getLandlordPokers()); + PokerHelper.sortPoker(clientSide.getPokers()); + + int currentClientId = clientSide.getId(); + room.setLandlordId(currentClientId); + room.setLastSellClient(currentClientId); + room.setCurrentSellClient(currentClientId); + clientSide.setType(ClientType.LANDLORD); + + for (ClientSide client : room.getClientSideList()) { + String result = MapHelper.newInstance() + .put("roomId", room.getId()) + .put("roomOwner", room.getRoomOwner()) + .put("roomClientCount", room.getClientSideList().size()) + .put("landlordNickname", clientSide.getNickname()) + .put("landlordId", clientSide.getId()) + .put("additionalPokers", room.getLandlordPokers()) + .json(); + + if (client.getRole() == ClientRole.PLAYER) { + ChannelUtils.pushToClient(client.getChannel(), ClientEventCode.CODE_GAME_LANDLORD_CONFIRM, result); + continue; + } + + if (currentClientId == client.getId()) { + RobotEventListener.get(ClientEventCode.CODE_GAME_POKER_PLAY).call(client, result); + } + } + + notifyWatcherConfirmLandlord(room, clientSide); + } + + /** + * 通知房间内的观战人员谁是地主 + * + * @param room 房间 + * @param landlord 地主 + */ + private void notifyWatcherConfirmLandlord(Room room, ClientSide landlord) { + String json = MapHelper.newInstance() + .put("landlord", landlord.getNickname()) + .put("additionalPokers", room.getLandlordPokers()) + .json(); + + for (ClientSide watcher : room.getWatcherList()) { + ChannelUtils.pushToClient(watcher.getChannel(), ClientEventCode.CODE_GAME_LANDLORD_CONFIRM, json); + } + } + + /** + * 通知房间内的观战人员抢地主情况 + * + * @param room 房间 + */ + private void notifyWatcherRobLandlord(Room room, ClientSide player) { + for (ClientSide watcher : room.getWatcherList()) { + ChannelUtils.pushToClient(watcher.getChannel(), ClientEventCode.CODE_GAME_LANDLORD_ELECT, player.getNickname()); + } + } +} diff --git a/landlords-server/src/main/java/org/nico/ratel/landlords/server/event/ServerEventListener_CODE_GAME_POKER_PLAY.java b/landlords-server/src/main/java/org/nico/ratel/landlords/server/event/ServerEventListener_CODE_GAME_POKER_PLAY.java new file mode 100644 index 0000000..1ee6c2e --- /dev/null +++ b/landlords-server/src/main/java/org/nico/ratel/landlords/server/event/ServerEventListener_CODE_GAME_POKER_PLAY.java @@ -0,0 +1,229 @@ +package org.nico.ratel.landlords.server.event; + +import java.util.ArrayList; +import java.util.List; + +import org.nico.noson.Noson; +import org.nico.ratel.landlords.channel.ChannelUtils; +import org.nico.ratel.landlords.entity.ClientSide; +import org.nico.ratel.landlords.entity.Poker; +import org.nico.ratel.landlords.entity.PokerSell; +import org.nico.ratel.landlords.entity.Room; +import org.nico.ratel.landlords.enums.*; +import org.nico.ratel.landlords.features.Features; +import org.nico.ratel.landlords.helper.MapHelper; +import org.nico.ratel.landlords.helper.PokerHelper; +import org.nico.ratel.landlords.print.SimplePrinter; +import org.nico.ratel.landlords.server.ServerContains; +import org.nico.ratel.landlords.server.robot.RobotEventListener; +import org.nico.ratel.landlords.utils.LastCardsUtils; + +public class ServerEventListener_CODE_GAME_POKER_PLAY implements ServerEventListener { + + @Override + public void call(ClientSide clientSide, String data) { + Room room = ServerContains.getRoom(clientSide.getRoomId()); + if (room == null) { + return; + } + if (room.getCurrentSellClient() != clientSide.getId()) { + ChannelUtils.pushToClient(clientSide.getChannel(), ClientEventCode.CODE_GAME_POKER_PLAY_ORDER_ERROR, null); + return; + } + Character[] options = Noson.convert(data, Character[].class); + int[] indexes = PokerHelper.getIndexes(options, clientSide.getPokers()); + if (!PokerHelper.checkPokerIndex(indexes, clientSide.getPokers())) { + ChannelUtils.pushToClient(clientSide.getChannel(), ClientEventCode.CODE_GAME_POKER_PLAY_INVALID, null); + return; + } + + boolean sellFlag = true; + List currentPokers = PokerHelper.getPoker(indexes, clientSide.getPokers()); + PokerSell currentPokerSell = PokerHelper.checkPokerType(currentPokers); + if (currentPokerSell.getSellType() == SellType.ILLEGAL) { + ChannelUtils.pushToClient(clientSide.getChannel(), ClientEventCode.CODE_GAME_POKER_PLAY_INVALID, null); + return; + } + if (room.getLastSellClient() != clientSide.getId() && room.getLastPokerShell() != null) { + PokerSell lastPokerSell = room.getLastPokerShell(); + + if ((lastPokerSell.getSellType() != currentPokerSell.getSellType() || lastPokerSell.getSellPokers().size() != currentPokerSell.getSellPokers().size()) && currentPokerSell.getSellType() != SellType.BOMB && currentPokerSell.getSellType() != SellType.KING_BOMB) { + String result = MapHelper.newInstance() + .put("playType", currentPokerSell.getSellType()) + .put("playCount", currentPokerSell.getSellPokers().size()) + .put("preType", lastPokerSell.getSellType()) + .put("preCount", lastPokerSell.getSellPokers().size()) + .json(); + ChannelUtils.pushToClient(clientSide.getChannel(), ClientEventCode.CODE_GAME_POKER_PLAY_MISMATCH, result); + return; + } + if (lastPokerSell.getScore() >= currentPokerSell.getScore()) { + String result = MapHelper.newInstance() + .put("playScore", currentPokerSell.getScore()) + .put("preScore", lastPokerSell.getScore()) + .json(); + ChannelUtils.pushToClient(clientSide.getChannel(), ClientEventCode.CODE_GAME_POKER_PLAY_LESS, result); + return; + } + } + + ClientSide next = clientSide.getNext(); + + if (currentPokerSell.getSellType() == SellType.BOMB || currentPokerSell.getSellType() == SellType.KING_BOMB) { + // 炸弹积分翻倍 + room.increaseRate(); + } + + room.setLastSellClient(clientSide.getId()); + room.setLastPokerShell(currentPokerSell); + room.setCurrentSellClient(next.getId()); + + List> lastPokerList = new ArrayList<>(); + for(int i = 0; i < room.getClientSideList().size(); i++){ + if(room.getClientSideList().get(i).getId() != clientSide.getId()){ + lastPokerList.add(room.getClientSideList().get(i).getPokers()); + } + } + String lastPokers = LastCardsUtils.getLastCards(lastPokerList); + lastPokerList = new ArrayList<>(); + clientSide.getPokers().removeAll(currentPokers); + MapHelper mapHelper = MapHelper.newInstance() + .put("clientId", clientSide.getId()) + .put("clientNickname", clientSide.getNickname()) + .put("clientType", clientSide.getType()) + .put("pokers", currentPokers) + .put("lastSellClientId", clientSide.getId()) + .put("lastSellPokers", currentPokers) + .put("lastPokers",lastPokers); + + if (!clientSide.getPokers().isEmpty()) { + mapHelper.put("sellClientNickname", next.getNickname()); + } + + String result = mapHelper.json(); + + for (ClientSide client : room.getClientSideList()) { + if (client.getRole() == ClientRole.PLAYER) { + ChannelUtils.pushToClient(client.getChannel(), ClientEventCode.CODE_SHOW_POKERS, result); + } + } + + notifyWatcherPlayPoker(room, result); + + if (!clientSide.getPokers().isEmpty()) { + if (next.getRole() == ClientRole.ROBOT) { + RobotEventListener.get(ClientEventCode.CODE_GAME_POKER_PLAY).call(next, data); + } else { + ServerEventListener.get(ServerEventCode.CODE_GAME_POKER_PLAY_REDIRECT).call(next, result); + } + return; + } + + gameOver(clientSide, room); +// ServerEventListener.get(ServerEventCode.CODE_GAME_STARTING).call(clientSide, data); + } + + private void setRoomClientScore(Room room, ClientType winnerType) { + int landLordScore = room.getScore() * 2; + int peasantScore = room.getScore(); + // 输的一方分数为负 + if (winnerType == ClientType.LANDLORD) { + peasantScore = -peasantScore; + } else { + landLordScore = -landLordScore; + } + for (ClientSide client : room.getClientSideList()) { + if (client.getType() == ClientType.LANDLORD) { + client.addScore(landLordScore); + } else { + client.addScore(peasantScore); + } + } + } + + private void gameOver(ClientSide winner, Room room) { + ClientType winnerType = winner.getType(); + if (isSpring(winner, room)) { + room.increaseRate(); + } + + setRoomClientScore(room, winnerType); + + ArrayList clientScores = new ArrayList<>(); + for (ClientSide client : room.getClientSideList()) { + MapHelper score = MapHelper.newInstance() + .put("clientId", client.getId()) + .put("nickName", client.getNickname()) + .put("score", client.getScore()) + .put("scoreInc", client.getScoreInc()) + .put("pokers", client.getPokers()); + clientScores.add(score.map()); + } + + SimplePrinter.serverLog(clientScores.toString()); + String result = MapHelper.newInstance() + .put("winnerNickname", winner.getNickname()) + .put("winnerType", winner.getType()) + .put("scores", clientScores) + .json(); + + boolean supportReady = true; + for (ClientSide client : room.getClientSideList()) { + if (client.getRole() == ClientRole.ROBOT || ! Features.supported(client.getVersion(), Features.READY)) { + supportReady = false; + break; + } + } + if (supportReady){ + room.setStatus(RoomStatus.WAIT); + room.initScoreRate(); + for (ClientSide client : room.getClientSideList()) { + client.setStatus(ClientStatus.NO_READY); + ChannelUtils.pushToClient(client.getChannel(), ClientEventCode.CODE_GAME_OVER, result); + } + }else{ + ServerEventListener.get(ServerEventCode.CODE_CLIENT_EXIT).call(winner, ""); + } + notifyWatcherGameOver(room, result); + } + + private boolean isSpring(ClientSide winner, Room room) { + boolean isSpring = true; + for (ClientSide client: room.getClientSideList()) { + if (client.getId() == winner.getId()) { + continue; + } + if (client.getType() == ClientType.PEASANT && client.getPokers().size() < 17) { + isSpring = false; + } + if (client.getType() == ClientType.LANDLORD && client.getPokers().size() < 20) { + isSpring = false; + } + } + return isSpring; + } + + /** + * 通知观战者出牌信息 + * + * @param room 房间 + * @param result 出牌信息 + */ + private void notifyWatcherPlayPoker(Room room, String result) { + for (ClientSide watcher : room.getWatcherList()) { + ChannelUtils.pushToClient(watcher.getChannel(), ClientEventCode.CODE_SHOW_POKERS, result); + } + } + + /** + * 通知观战者游戏结束 + * + * @param room 房间 + * @param result 出牌信息 + */ + private void notifyWatcherGameOver(Room room, String result) { + for (ClientSide watcher : room.getWatcherList()) { + ChannelUtils.pushToClient(watcher.getChannel(), ClientEventCode.CODE_GAME_OVER, result); + } + } +} diff --git a/landlords-server/src/main/java/org/nico/ratel/landlords/server/event/ServerEventListener_CODE_GAME_POKER_PLAY_PASS.java b/landlords-server/src/main/java/org/nico/ratel/landlords/server/event/ServerEventListener_CODE_GAME_POKER_PLAY_PASS.java new file mode 100644 index 0000000..0d23fb4 --- /dev/null +++ b/landlords-server/src/main/java/org/nico/ratel/landlords/server/event/ServerEventListener_CODE_GAME_POKER_PLAY_PASS.java @@ -0,0 +1,64 @@ +package org.nico.ratel.landlords.server.event; + +import org.nico.ratel.landlords.channel.ChannelUtils; +import org.nico.ratel.landlords.entity.ClientSide; +import org.nico.ratel.landlords.entity.Room; +import org.nico.ratel.landlords.enums.ClientEventCode; +import org.nico.ratel.landlords.enums.ClientRole; +import org.nico.ratel.landlords.helper.MapHelper; +import org.nico.ratel.landlords.server.ServerContains; +import org.nico.ratel.landlords.server.robot.RobotEventListener; + +public class ServerEventListener_CODE_GAME_POKER_PLAY_PASS implements ServerEventListener { + + @Override + public void call(ClientSide clientSide, String data) { + Room room = ServerContains.getRoom(clientSide.getRoomId()); + + if(room != null) { + if(room.getCurrentSellClient() == clientSide.getId()) { + if(clientSide.getId() != room.getLastSellClient()) { + ClientSide turnClient = clientSide.getNext(); + + room.setCurrentSellClient(turnClient.getId()); + + for(ClientSide client: room.getClientSideList()) { + String result = MapHelper.newInstance() + .put("clientId", clientSide.getId()) + .put("clientNickname", clientSide.getNickname()) + .put("nextClientId", turnClient.getId()) + .put("nextClientNickname", turnClient.getNickname()) + .json(); + if(client.getRole() == ClientRole.PLAYER) { + ChannelUtils.pushToClient(client.getChannel(), ClientEventCode.CODE_GAME_POKER_PLAY_PASS, result); + }else { + if(client.getId() == turnClient.getId()) { + RobotEventListener.get(ClientEventCode.CODE_GAME_POKER_PLAY).call(turnClient, data); + } + } + } + + notifyWatcherPlayPass(room, clientSide); + }else { + ChannelUtils.pushToClient(clientSide.getChannel(), ClientEventCode.CODE_GAME_POKER_PLAY_CANT_PASS, null); + } + }else { + ChannelUtils.pushToClient(clientSide.getChannel(), ClientEventCode.CODE_GAME_POKER_PLAY_ORDER_ERROR, null); + } + }else { +// ChannelUtils.pushToClient(clientSide.getChannel(), ClientEventCode.CODE_ROOM_PLAY_FAIL_BY_INEXIST, null); + } + } + + /** + * 通知观战者玩家不出牌 + * + * @param room 房间 + * @param player 不出牌的玩家 + */ + private void notifyWatcherPlayPass(Room room, ClientSide player) { + for (ClientSide watcher : room.getWatcherList()) { + ChannelUtils.pushToClient(watcher.getChannel(), ClientEventCode.CODE_GAME_POKER_PLAY_PASS, player.getNickname()); + } + } +} diff --git a/landlords-server/src/main/java/org/nico/ratel/landlords/server/event/ServerEventListener_CODE_GAME_POKER_PLAY_REDIRECT.java b/landlords-server/src/main/java/org/nico/ratel/landlords/server/event/ServerEventListener_CODE_GAME_POKER_PLAY_REDIRECT.java new file mode 100644 index 0000000..87c8996 --- /dev/null +++ b/landlords-server/src/main/java/org/nico/ratel/landlords/server/event/ServerEventListener_CODE_GAME_POKER_PLAY_REDIRECT.java @@ -0,0 +1,63 @@ +package org.nico.ratel.landlords.server.event; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.nico.noson.Noson; +import org.nico.noson.util.string.StringUtils; +import org.nico.ratel.landlords.channel.ChannelUtils; +import org.nico.ratel.landlords.entity.ClientSide; +import org.nico.ratel.landlords.entity.Poker; +import org.nico.ratel.landlords.entity.Room; +import org.nico.ratel.landlords.enums.ClientEventCode; +import org.nico.ratel.landlords.helper.MapHelper; +import org.nico.ratel.landlords.server.ServerContains; +import org.nico.ratel.landlords.utils.LastCardsUtils; + +public class ServerEventListener_CODE_GAME_POKER_PLAY_REDIRECT implements ServerEventListener{ + + @Override + public void call(ClientSide clientSide, String data) { + Room room = ServerContains.getRoom(clientSide.getRoomId()); + Map datas = new HashMap(); + if(StringUtils.isNotBlank(data)) { + datas = Noson.parseMap(data); + } + + List> clientInfos = new ArrayList>(3); + for(ClientSide client : room.getClientSideList()) { + if(clientSide.getId() != client.getId()) { + clientInfos.add(MapHelper.newInstance() + .put("clientId", client.getId()) + .put("clientNickname", client.getNickname()) + .put("type", client.getType()) + .put("surplus", client.getPokers().size()) + .put("position", clientSide.getPre().getId() == client.getId() ? "UP" : "DOWN") + .map()); + } + } + + List> lastPokerList = new ArrayList<>(); + for(int i = 0; i < room.getClientSideList().size(); i++){ + if(room.getClientSideList().get(i).getId() != clientSide.getId()){ + lastPokerList.add(room.getClientSideList().get(i).getPokers()); + } + } + String lastPokers = LastCardsUtils.getLastCards(lastPokerList); + lastPokerList = new ArrayList<>(); + String result = MapHelper.newInstance() + .put("pokers", clientSide.getPokers()) + .put("lastSellPokers", datas.get("lastSellPokers")) + .put("lastSellClientId", datas.get("lastSellClientId")) + .put("clientInfos", clientInfos) + .put("sellClientId", room.getCurrentSellClient()) + .put("sellClientNickname", ServerContains.CLIENT_SIDE_MAP.get(room.getCurrentSellClient()).getNickname()) + .put("lastPokers",lastPokers) + .json(); + + ChannelUtils.pushToClient(clientSide.getChannel(), ClientEventCode.CODE_GAME_POKER_PLAY_REDIRECT, result); + } + +} diff --git a/landlords-server/src/main/java/org/nico/ratel/landlords/server/event/ServerEventListener_CODE_GAME_READY.java b/landlords-server/src/main/java/org/nico/ratel/landlords/server/event/ServerEventListener_CODE_GAME_READY.java new file mode 100644 index 0000000..0752045 --- /dev/null +++ b/landlords-server/src/main/java/org/nico/ratel/landlords/server/event/ServerEventListener_CODE_GAME_READY.java @@ -0,0 +1,57 @@ +package org.nico.ratel.landlords.server.event; + +import org.nico.ratel.landlords.channel.ChannelUtils; +import org.nico.ratel.landlords.entity.ClientSide; +import org.nico.ratel.landlords.entity.Room; +import org.nico.ratel.landlords.enums.*; +import org.nico.ratel.landlords.helper.MapHelper; +import org.nico.ratel.landlords.print.SimplePrinter; +import org.nico.ratel.landlords.server.ServerContains; + +import java.util.concurrent.ConcurrentSkipListMap; + +public class ServerEventListener_CODE_GAME_READY implements ServerEventListener { + @Override + public void call(ClientSide clientSide, String data) { + Room room = ServerContains.getRoom(clientSide.getRoomId()); + if (room == null) { + return; + } + SimplePrinter.serverLog("房间状态:" + room.getStatus()); + SimplePrinter.serverLog("玩家状态:" + clientSide.getStatus()); + if (room.getStatus() == RoomStatus.STARTING) { + return; + } + if (clientSide.getStatus() == ClientStatus.PLAYING || clientSide.getStatus() == ClientStatus.TO_CHOOSE || clientSide.getStatus() == ClientStatus.CALL_LANDLORD) { + return; + } + clientSide.setStatus(clientSide.getStatus() == ClientStatus.READY ? ClientStatus.NO_READY : ClientStatus.READY); + String result = MapHelper.newInstance() + .put("clientNickName", clientSide.getNickname()) + .put("status", clientSide.getStatus()) + .put("clientId", clientSide.getId()) + .json(); + boolean allReady = true; + ConcurrentSkipListMap roomClientMap = (ConcurrentSkipListMap) room.getClientSideMap(); + if (roomClientMap.size() < 3) { + allReady = false; + } else { + for (ClientSide client : room.getClientSideList()) { + if (client.getRole() == ClientRole.PLAYER && client.getStatus() != ClientStatus.READY) { + allReady = false; + break; + } + } + } + + for (ClientSide client : room.getClientSideList()) { + if (client.getRole() == ClientRole.PLAYER) { + ChannelUtils.pushToClient(client.getChannel(), ClientEventCode.CODE_GAME_READY, result); + } + } + + if (allReady) { + ServerEventListener.get(ServerEventCode.CODE_GAME_STARTING).call(clientSide, data); + } + } +} diff --git a/landlords-server/src/main/java/org/nico/ratel/landlords/server/event/ServerEventListener_CODE_GAME_STARTING.java b/landlords-server/src/main/java/org/nico/ratel/landlords/server/event/ServerEventListener_CODE_GAME_STARTING.java new file mode 100644 index 0000000..1372300 --- /dev/null +++ b/landlords-server/src/main/java/org/nico/ratel/landlords/server/event/ServerEventListener_CODE_GAME_STARTING.java @@ -0,0 +1,99 @@ +package org.nico.ratel.landlords.server.event; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; + +import org.nico.ratel.landlords.channel.ChannelUtils; +import org.nico.ratel.landlords.entity.ClientSide; +import org.nico.ratel.landlords.entity.Poker; +import org.nico.ratel.landlords.entity.Room; +import org.nico.ratel.landlords.enums.*; +import org.nico.ratel.landlords.helper.MapHelper; +import org.nico.ratel.landlords.helper.PokerHelper; +import org.nico.ratel.landlords.server.ServerContains; +import org.nico.ratel.landlords.server.robot.RobotEventListener; +import org.nico.ratel.landlords.utils.JsonUtils; +import org.nico.ratel.landlords.utils.LastCardsUtils; + +public class ServerEventListener_CODE_GAME_STARTING implements ServerEventListener { + + @Override + public void call(ClientSide clientSide, String data) { + + Room room = ServerContains.getRoom(clientSide.getRoomId()); + + LinkedList roomClientList = room.getClientSideList(); + + // Send the points of poker + List> pokersList = PokerHelper.distributePoker(); + int cursor = 0; + for (ClientSide client : roomClientList) { + client.setPokers(pokersList.get(cursor++)); + } + room.setLandlordPokers(pokersList.get(3)); + + // Push information about the robber + int startGrabIndex = (int) (Math.random() * 3); + ClientSide startGrabClient = roomClientList.get(startGrabIndex); + room.setCurrentSellClient(startGrabClient.getId()); + + // Push start game messages + room.setStatus(RoomStatus.STARTING); + room.setCreateTime(System.currentTimeMillis()); + room.setLastFlushTime(System.currentTimeMillis()); + + // Record the first speaker + room.setFirstSellClient(startGrabClient.getId()); + List> otherPokers = new ArrayList<>(); + for (ClientSide client : roomClientList) { + client.setType(ClientType.PEASANT); + client.setStatus(ClientStatus.PLAYING); + for(ClientSide otherClient : roomClientList){ + if(otherClient.getId() != client.getId()){ + otherPokers.add(otherClient.getPokers()); + } + } + String lastCards = LastCardsUtils.getLastCards(otherPokers); + otherPokers = new ArrayList<>(); + String result = MapHelper.newInstance() + .put("roomId", room.getId()) + .put("roomOwner", room.getRoomOwner()) + .put("roomClientCount", room.getClientSideList().size()) + .put("nextClientNickname", startGrabClient.getNickname()) + .put("nextClientId", startGrabClient.getId()) + .put("pokers", client.getPokers()) + .put("lastPokers",lastCards) + .json(); + + if (client.getRole() == ClientRole.PLAYER) { + ChannelUtils.pushToClient(client.getChannel(), ClientEventCode.CODE_GAME_STARTING, result); + } else { + if (startGrabClient.getId() == client.getId()) { + RobotEventListener.get(ClientEventCode.CODE_GAME_LANDLORD_ELECT).call(client, result); + } + } + + } + + notifyWatcherGameStart(room); + } + + + /** + * 通知房间内的观战人员游戏开始 + * + * @param room 房间 + */ + private void notifyWatcherGameStart(Room room) { + String result = MapHelper.newInstance() + .put("player1", room.getClientSideList().getFirst().getNickname()) + .put("player2", room.getClientSideList().getFirst().getNext().getNickname()) + .put("player3", room.getClientSideList().getLast().getNickname()) + .json(); + for (ClientSide clientSide : room.getWatcherList()) { + ChannelUtils.pushToClient(clientSide.getChannel(), ClientEventCode.CODE_GAME_STARTING, result); + } + } + +} diff --git a/landlords-server/src/main/java/org/nico/ratel/landlords/server/event/ServerEventListener_CODE_GAME_WATCH.java b/landlords-server/src/main/java/org/nico/ratel/landlords/server/event/ServerEventListener_CODE_GAME_WATCH.java new file mode 100644 index 0000000..532498f --- /dev/null +++ b/landlords-server/src/main/java/org/nico/ratel/landlords/server/event/ServerEventListener_CODE_GAME_WATCH.java @@ -0,0 +1,37 @@ +package org.nico.ratel.landlords.server.event; + +import org.nico.noson.Noson; +import org.nico.ratel.landlords.channel.ChannelUtils; +import org.nico.ratel.landlords.entity.ClientSide; +import org.nico.ratel.landlords.entity.Room; +import org.nico.ratel.landlords.enums.ClientEventCode; +import org.nico.ratel.landlords.helper.MapHelper; +import org.nico.ratel.landlords.server.ServerContains; + +import java.util.HashMap; +import java.util.Map; + +public class ServerEventListener_CODE_GAME_WATCH implements ServerEventListener { + + @Override + public void call(ClientSide clientSide, String data) { + Room room = ServerContains.getRoom(Integer.parseInt(data)); + + if (room == null) { + String result = MapHelper.newInstance() + .put("roomId", data) + .json(); + + ChannelUtils.pushToClient(clientSide.getChannel(), ClientEventCode.CODE_ROOM_JOIN_FAIL_BY_INEXIST, result); + } else { + // 将用户加入到房间中的观战者列表中 + clientSide.setRoomId(room.getId()); + room.getWatcherList().add(clientSide); + + Map map = new HashMap<>(16); + map.put("owner", room.getRoomOwner()); + map.put("status", room.getStatus().toString()); + ChannelUtils.pushToClient(clientSide.getChannel(), ClientEventCode.CODE_GAME_WATCH_SUCCESSFUL, Noson.reversal(map)); + } + } +} diff --git a/landlords-server/src/main/java/org/nico/ratel/landlords/server/event/ServerEventListener_CODE_GAME_WATCH_EXIT.java b/landlords-server/src/main/java/org/nico/ratel/landlords/server/event/ServerEventListener_CODE_GAME_WATCH_EXIT.java new file mode 100644 index 0000000..1484f29 --- /dev/null +++ b/landlords-server/src/main/java/org/nico/ratel/landlords/server/event/ServerEventListener_CODE_GAME_WATCH_EXIT.java @@ -0,0 +1,23 @@ +package org.nico.ratel.landlords.server.event; + +import org.nico.ratel.landlords.entity.ClientSide; +import org.nico.ratel.landlords.entity.Room; +import org.nico.ratel.landlords.print.SimplePrinter; +import org.nico.ratel.landlords.server.ServerContains; + +public class ServerEventListener_CODE_GAME_WATCH_EXIT implements ServerEventListener { + + @Override + public void call(ClientSide clientSide, String data) { + Room room = ServerContains.getRoom(clientSide.getRoomId()); + + if (room != null) { + // 房间如果存在,则将观战者从房间观战列表中移除 + clientSide.setRoomId(room.getId()); + boolean successful = room.getWatcherList().remove(clientSide); + if (successful) { + SimplePrinter.serverLog(clientSide.getNickname() + " exit room " + room.getId()); + } + } + } +} diff --git a/landlords-server/src/main/java/org/nico/ratel/landlords/server/event/ServerEventListener_CODE_GET_ROOMS.java b/landlords-server/src/main/java/org/nico/ratel/landlords/server/event/ServerEventListener_CODE_GET_ROOMS.java new file mode 100644 index 0000000..611fdc0 --- /dev/null +++ b/landlords-server/src/main/java/org/nico/ratel/landlords/server/event/ServerEventListener_CODE_GET_ROOMS.java @@ -0,0 +1,33 @@ +package org.nico.ratel.landlords.server.event; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import org.nico.noson.Noson; +import org.nico.ratel.landlords.channel.ChannelUtils; +import org.nico.ratel.landlords.entity.ClientSide; +import org.nico.ratel.landlords.entity.Room; +import org.nico.ratel.landlords.enums.ClientEventCode; +import org.nico.ratel.landlords.helper.MapHelper; +import org.nico.ratel.landlords.server.ServerContains; + +public class ServerEventListener_CODE_GET_ROOMS implements ServerEventListener { + + @Override + public void call(ClientSide clientSide, String data) { + List> roomList = new ArrayList<>(ServerContains.getRoomMap().size()); + for (Entry entry : ServerContains.getRoomMap().entrySet()) { + Room room = entry.getValue(); + roomList.add(MapHelper.newInstance() + .put("roomId", room.getId()) + .put("roomOwner", room.getRoomOwner()) + .put("roomClientCount", room.getClientSideList().size()) + .put("roomType", room.getType()) + .map()); + } + ChannelUtils.pushToClient(clientSide.getChannel(), ClientEventCode.CODE_SHOW_ROOMS, Noson.reversal(roomList)); + } + +} diff --git a/landlords-server/src/main/java/org/nico/ratel/landlords/server/event/ServerEventListener_CODE_ROOM_CREATE.java b/landlords-server/src/main/java/org/nico/ratel/landlords/server/event/ServerEventListener_CODE_ROOM_CREATE.java new file mode 100644 index 0000000..3b3ff0a --- /dev/null +++ b/landlords-server/src/main/java/org/nico/ratel/landlords/server/event/ServerEventListener_CODE_ROOM_CREATE.java @@ -0,0 +1,35 @@ +package org.nico.ratel.landlords.server.event; + +import org.nico.noson.Noson; +import org.nico.ratel.landlords.channel.ChannelUtils; +import org.nico.ratel.landlords.entity.ClientSide; +import org.nico.ratel.landlords.entity.Room; +import org.nico.ratel.landlords.enums.ClientEventCode; +import org.nico.ratel.landlords.enums.ClientStatus; +import org.nico.ratel.landlords.enums.RoomStatus; +import org.nico.ratel.landlords.enums.RoomType; +import org.nico.ratel.landlords.server.ServerContains; + +public class ServerEventListener_CODE_ROOM_CREATE implements ServerEventListener { + + @Override + public void call(ClientSide clientSide, String data) { + + Room room = new Room(ServerContains.getServerId()); + room.setStatus(RoomStatus.WAIT); + room.setType(RoomType.PVP); + room.setRoomOwner(clientSide.getNickname()); + room.getClientSideMap().put(clientSide.getId(), clientSide); + room.getClientSideList().add(clientSide); + room.setCurrentSellClient(clientSide.getId()); + room.setCreateTime(System.currentTimeMillis()); + room.setLastFlushTime(System.currentTimeMillis()); + + clientSide.setRoomId(room.getId()); + ServerContains.addRoom(room); + + clientSide.setStatus(ClientStatus.NO_READY); + + ChannelUtils.pushToClient(clientSide.getChannel(), ClientEventCode.CODE_ROOM_CREATE_SUCCESS, Noson.reversal(room)); + } +} diff --git a/landlords-server/src/main/java/org/nico/ratel/landlords/server/event/ServerEventListener_CODE_ROOM_CREATE_PVE.java b/landlords-server/src/main/java/org/nico/ratel/landlords/server/event/ServerEventListener_CODE_ROOM_CREATE_PVE.java new file mode 100644 index 0000000..586c589 --- /dev/null +++ b/landlords-server/src/main/java/org/nico/ratel/landlords/server/event/ServerEventListener_CODE_ROOM_CREATE_PVE.java @@ -0,0 +1,56 @@ +package org.nico.ratel.landlords.server.event; + +import org.nico.ratel.landlords.channel.ChannelUtils; +import org.nico.ratel.landlords.entity.ClientSide; +import org.nico.ratel.landlords.entity.Room; +import org.nico.ratel.landlords.enums.*; +import org.nico.ratel.landlords.robot.RobotDecisionMakers; +import org.nico.ratel.landlords.server.ServerContains; + +public class ServerEventListener_CODE_ROOM_CREATE_PVE implements ServerEventListener { + + @Override + public void call(ClientSide clientSide, String data) { + + int difficultyCoefficient = Integer.parseInt(data); + if (!RobotDecisionMakers.contains(difficultyCoefficient)) { + ChannelUtils.pushToClient(clientSide.getChannel(), ClientEventCode.CODE_PVE_DIFFICULTY_NOT_SUPPORT, null); + return; + } + + Room room = new Room(ServerContains.getServerId()); + room.setType(RoomType.PVE); + room.setStatus(RoomStatus.BLANK); + room.setRoomOwner(clientSide.getNickname()); + room.getClientSideMap().put(clientSide.getId(), clientSide); + room.getClientSideList().add(clientSide); + room.setCurrentSellClient(clientSide.getId()); + room.setCreateTime(System.currentTimeMillis()); + room.setDifficultyCoefficient(difficultyCoefficient); + + clientSide.setRoomId(room.getId()); + ServerContains.addRoom(room); + + ClientSide preClient = clientSide; + //Add robots + for (int index = 1; index < 3; index++) { + ClientSide robot = new ClientSide(-ServerContains.getClientId(), ClientStatus.PLAYING, null); + robot.setNickname("robot_" + index); + robot.setRole(ClientRole.ROBOT); + preClient.setNext(robot); + robot.setPre(preClient); + robot.setRoomId(room.getId()); + room.getClientSideMap().put(robot.getId(), robot); + room.getClientSideList().add(robot); + + preClient = robot; + ServerContains.CLIENT_SIDE_MAP.put(robot.getId(), robot); + } + preClient.setNext(clientSide); + clientSide.setPre(preClient); + + ServerEventListener.get(ServerEventCode.CODE_GAME_STARTING).call(clientSide, String.valueOf(room.getId())); + } + + +} diff --git a/landlords-server/src/main/java/org/nico/ratel/landlords/server/event/ServerEventListener_CODE_ROOM_JOIN.java b/landlords-server/src/main/java/org/nico/ratel/landlords/server/event/ServerEventListener_CODE_ROOM_JOIN.java new file mode 100644 index 0000000..ca24ab4 --- /dev/null +++ b/landlords-server/src/main/java/org/nico/ratel/landlords/server/event/ServerEventListener_CODE_ROOM_JOIN.java @@ -0,0 +1,87 @@ +package org.nico.ratel.landlords.server.event; + +import java.util.LinkedList; +import java.util.concurrent.ConcurrentSkipListMap; + +import org.nico.ratel.landlords.channel.ChannelUtils; +import org.nico.ratel.landlords.entity.ClientSide; +import org.nico.ratel.landlords.entity.Room; +import org.nico.ratel.landlords.enums.ClientEventCode; +import org.nico.ratel.landlords.enums.ClientStatus; +import org.nico.ratel.landlords.enums.RoomStatus; +import org.nico.ratel.landlords.enums.ServerEventCode; +import org.nico.ratel.landlords.helper.MapHelper; +import org.nico.ratel.landlords.server.ServerContains; + +public class ServerEventListener_CODE_ROOM_JOIN implements ServerEventListener { + + @Override + public void call(ClientSide clientSide, String data) { + + Room room = ServerContains.getRoom(Integer.parseInt(data)); + + if (room == null) { + String result = MapHelper.newInstance() + .put("roomId", data) + .json(); + ChannelUtils.pushToClient(clientSide.getChannel(), ClientEventCode.CODE_ROOM_JOIN_FAIL_BY_INEXIST, result); + return; + } + if (room.getClientSideList().size() == 3) { + String result = MapHelper.newInstance() + .put("roomId", room.getId()) + .put("roomOwner", room.getRoomOwner()) + .json(); + ChannelUtils.pushToClient(clientSide.getChannel(), ClientEventCode.CODE_ROOM_JOIN_FAIL_BY_FULL, result); + return; + } + // join default ready + clientSide.setStatus(ClientStatus.READY); + clientSide.setRoomId(room.getId()); + + ConcurrentSkipListMap roomClientMap = (ConcurrentSkipListMap) room.getClientSideMap(); + LinkedList roomClientList = room.getClientSideList(); + + if (roomClientList.size() > 0) { + ClientSide pre = roomClientList.getLast(); + pre.setNext(clientSide); + clientSide.setPre(pre); + } + + roomClientList.add(clientSide); + roomClientMap.put(clientSide.getId(), clientSide); + + if (roomClientMap.size() == 3) { + clientSide.setNext(roomClientList.getFirst()); + roomClientList.getFirst().setPre(clientSide); + + ServerEventListener.get(ServerEventCode.CODE_GAME_STARTING).call(clientSide, String.valueOf(room.getId())); + return; + } + room.setStatus(RoomStatus.WAIT); + String result = MapHelper.newInstance() + .put("clientId", clientSide.getId()) + .put("clientNickname", clientSide.getNickname()) + .put("roomId", room.getId()) + .put("roomOwner", room.getRoomOwner()) + .put("roomClientCount", room.getClientSideList().size()) + .json(); + for (ClientSide client : roomClientMap.values()) { + ChannelUtils.pushToClient(client.getChannel(), ClientEventCode.CODE_ROOM_JOIN_SUCCESS, result); + } + + notifyWatcherJoinRoom(room, clientSide); + } + + /** + * 通知观战者玩家加入房间 + * + * @param room 房间 + * @param clientSide 玩家 + */ + private void notifyWatcherJoinRoom(Room room, ClientSide clientSide) { + for (ClientSide watcher : room.getWatcherList()) { + ChannelUtils.pushToClient(watcher.getChannel(), ClientEventCode.CODE_ROOM_JOIN_SUCCESS, clientSide.getNickname()); + } + } +} diff --git a/landlords-server/src/main/java/org/nico/ratel/landlords/server/handler/ProtobufTransferHandler.java b/landlords-server/src/main/java/org/nico/ratel/landlords/server/handler/ProtobufTransferHandler.java new file mode 100644 index 0000000..294630e --- /dev/null +++ b/landlords-server/src/main/java/org/nico/ratel/landlords/server/handler/ProtobufTransferHandler.java @@ -0,0 +1,94 @@ +package org.nico.ratel.landlords.server.handler; + +import org.nico.ratel.landlords.channel.ChannelUtils; +import org.nico.ratel.landlords.entity.ClientSide; +import org.nico.ratel.landlords.entity.ServerTransferData.ServerTransferDataProtoc; +import org.nico.ratel.landlords.enums.ClientEventCode; +import org.nico.ratel.landlords.enums.ClientRole; +import org.nico.ratel.landlords.enums.ClientStatus; +import org.nico.ratel.landlords.enums.ServerEventCode; +import org.nico.ratel.landlords.print.SimplePrinter; +import org.nico.ratel.landlords.server.ServerContains; +import org.nico.ratel.landlords.server.event.ServerEventListener; + +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.handler.timeout.IdleState; +import io.netty.handler.timeout.IdleStateEvent; + +public class ProtobufTransferHandler extends ChannelInboundHandlerAdapter { + + @Override + public void handlerRemoved(ChannelHandlerContext ctx) { + ClientSide client = ServerContains.CLIENT_SIDE_MAP.get(getId(ctx.channel())); + SimplePrinter.serverLog("client " + client.getId() + "(" + client.getNickname() + ") disconnected"); + clientOfflineEvent(ctx.channel()); + ctx.channel().close(); + } + + @Override + public void channelRegistered(ChannelHandlerContext ctx) throws Exception { + Channel ch = ctx.channel(); + + //init client info + ClientSide clientSide = new ClientSide(getId(ctx.channel()), ClientStatus.TO_CHOOSE, ch); + clientSide.setNickname(String.valueOf(clientSide.getId())); + clientSide.setRole(ClientRole.PLAYER); + + ServerContains.CLIENT_SIDE_MAP.put(clientSide.getId(), clientSide); + SimplePrinter.serverLog("Has client connect to the server: " + clientSide.getId()); + + ChannelUtils.pushToClient(ch, ClientEventCode.CODE_CLIENT_CONNECT, String.valueOf(clientSide.getId())); + ChannelUtils.pushToClient(ch, ClientEventCode.CODE_CLIENT_NICKNAME_SET, null); + } + + + @Override + public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { + if (msg instanceof ServerTransferDataProtoc) { + ServerTransferDataProtoc serverTransferData = (ServerTransferDataProtoc) msg; + ServerEventCode code = ServerEventCode.valueOf(serverTransferData.getCode()); + if (code != ServerEventCode.CODE_CLIENT_HEAD_BEAT) { + ClientSide client = ServerContains.CLIENT_SIDE_MAP.get(getId(ctx.channel())); + SimplePrinter.serverLog(client.getId() + " | " + client.getNickname() + " do:" + code.getMsg()); + ServerEventListener.get(code).call(client, serverTransferData.getData()); + } + } + } + + @Override + public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { + if (evt instanceof IdleStateEvent) { + IdleStateEvent event = (IdleStateEvent) evt; + if (event.state() == IdleState.READER_IDLE) { + try { + clientOfflineEvent(ctx.channel()); + ctx.channel().close(); + } catch (Exception ignore) { + } + } + } else { + super.userEventTriggered(ctx, evt); + } + } + + private int getId(Channel channel) { + String longId = channel.id().asLongText(); + Integer clientId = ServerContains.CHANNEL_ID_MAP.get(longId); + if (null == clientId) { + clientId = ServerContains.getClientId(); + ServerContains.CHANNEL_ID_MAP.put(longId, clientId); + } + return clientId; + } + + private void clientOfflineEvent(Channel channel) { + int clientId = getId(channel); + ClientSide client = ServerContains.CLIENT_SIDE_MAP.get(clientId); + if (client != null) { + SimplePrinter.serverLog("Has client exit to the server:" + clientId + " | " + client.getNickname()); + ServerEventListener.get(ServerEventCode.CODE_CLIENT_OFFLINE).call(client, null); + } + } +} diff --git a/landlords-server/src/main/java/org/nico/ratel/landlords/server/handler/SecondProtobufCodec.java b/landlords-server/src/main/java/org/nico/ratel/landlords/server/handler/SecondProtobufCodec.java new file mode 100644 index 0000000..77884ab --- /dev/null +++ b/landlords-server/src/main/java/org/nico/ratel/landlords/server/handler/SecondProtobufCodec.java @@ -0,0 +1,25 @@ +package org.nico.ratel.landlords.server.handler; + +import java.util.List; + +import org.nico.ratel.landlords.entity.ServerTransferData.ServerTransferDataProtoc; + +import com.google.protobuf.MessageLite; + +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.MessageToMessageCodec; + +public class SecondProtobufCodec extends MessageToMessageCodec { + + @Override + protected void encode(ChannelHandlerContext ctx, MessageLite msg, List out) { + out.add(msg); + } + + @Override + protected void decode(ChannelHandlerContext ctx, ServerTransferDataProtoc msg, List out) { + out.add(msg); + } + + +} diff --git a/landlords-server/src/main/java/org/nico/ratel/landlords/server/handler/WebsocketTransferHandler.java b/landlords-server/src/main/java/org/nico/ratel/landlords/server/handler/WebsocketTransferHandler.java new file mode 100644 index 0000000..d6f2173 --- /dev/null +++ b/landlords-server/src/main/java/org/nico/ratel/landlords/server/handler/WebsocketTransferHandler.java @@ -0,0 +1,103 @@ +package org.nico.ratel.landlords.server.handler; + +import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelInboundHandlerAdapter; +import io.netty.channel.SimpleChannelInboundHandler; +import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; +import io.netty.handler.timeout.IdleState; +import io.netty.handler.timeout.IdleStateEvent; +import org.nico.ratel.landlords.channel.ChannelUtils; +import org.nico.ratel.landlords.entity.ClientSide; +import org.nico.ratel.landlords.entity.Msg; +import org.nico.ratel.landlords.entity.ServerTransferData.ServerTransferDataProtoc; +import org.nico.ratel.landlords.enums.ClientEventCode; +import org.nico.ratel.landlords.enums.ClientRole; +import org.nico.ratel.landlords.enums.ClientStatus; +import org.nico.ratel.landlords.enums.ServerEventCode; +import org.nico.ratel.landlords.print.SimplePrinter; +import org.nico.ratel.landlords.server.ServerContains; +import org.nico.ratel.landlords.server.event.ServerEventListener; +import org.nico.ratel.landlords.utils.JsonUtils; + +import java.util.Objects; + +public class WebsocketTransferHandler extends SimpleChannelInboundHandler { + + @Override + public void channelRegistered(ChannelHandlerContext ctx) throws Exception { + Channel ch = ctx.channel(); + + //init client info + ClientSide clientSide = new ClientSide(getId(ctx.channel()), ClientStatus.TO_CHOOSE, ch); + clientSide.setNickname(String.valueOf(clientSide.getId())); + clientSide.setRole(ClientRole.PLAYER); + + ServerContains.CLIENT_SIDE_MAP.put(clientSide.getId(), clientSide); + SimplePrinter.serverLog("Has client connect to the server:" + clientSide.getId()); + new Thread(()->{ + try { + Thread.sleep(2000L); + ChannelUtils.pushToClient(ch, ClientEventCode.CODE_CLIENT_CONNECT, String.valueOf(clientSide.getId())); + ChannelUtils.pushToClient(ch, ClientEventCode.CODE_CLIENT_NICKNAME_SET, null); + } catch (InterruptedException ignored) { + } + }).start(); + } + + @Override + protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame frame) throws Exception { + Msg msg = JsonUtils.fromJson(frame.text(), Msg.class); + ServerEventCode code = ServerEventCode.valueOf(msg.getCode()); + if (! Objects.equals(code, ServerEventCode.CODE_CLIENT_HEAD_BEAT)){ + ClientSide client = ServerContains.CLIENT_SIDE_MAP.get(getId(ctx.channel())); + SimplePrinter.serverLog(client.getId() + " | " + client.getNickname() + " do:" + code.getMsg()); + ServerEventListener.get(code).call(client, msg.getData()); + } + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { + if(cause instanceof java.io.IOException) { + clientOfflineEvent(ctx.channel()); + }else { + SimplePrinter.serverLog("ERROR:" + cause.getMessage()); + cause.printStackTrace(); + } + } + + @Override + public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { + if (evt instanceof IdleStateEvent) { + IdleStateEvent event = (IdleStateEvent) evt; + if (event.state() == IdleState.READER_IDLE) { + try{ + clientOfflineEvent(ctx.channel()); + ctx.channel().close(); + }catch(Exception e){ + } + } + } else { + super.userEventTriggered(ctx, evt); + } + } + + private int getId(Channel channel){ + String longId = channel.id().asLongText(); + Integer clientId = ServerContains.CHANNEL_ID_MAP.get(longId); + if(null == clientId){ + clientId = ServerContains.getClientId(); + ServerContains.CHANNEL_ID_MAP.put(longId, clientId); + } + return clientId; + } + + private void clientOfflineEvent(Channel channel){ + int clientId = getId(channel); + ClientSide client = ServerContains.CLIENT_SIDE_MAP.get(clientId); + if(client != null) { + SimplePrinter.serverLog("Has client exit to the server:" + clientId + " | " + client.getNickname()); + ServerEventListener.get(ServerEventCode.CODE_CLIENT_OFFLINE).call(client, null); + } + } +} diff --git a/landlords-server/src/main/java/org/nico/ratel/landlords/server/proxy/ProtobufProxy.java b/landlords-server/src/main/java/org/nico/ratel/landlords/server/proxy/ProtobufProxy.java new file mode 100644 index 0000000..be1facd --- /dev/null +++ b/landlords-server/src/main/java/org/nico/ratel/landlords/server/proxy/ProtobufProxy.java @@ -0,0 +1,71 @@ +package org.nico.ratel.landlords.server.proxy; + +import io.netty.bootstrap.ServerBootstrap; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelInitializer; +import io.netty.channel.EventLoopGroup; +import io.netty.channel.epoll.Epoll; +import io.netty.channel.epoll.EpollEventLoopGroup; +import io.netty.channel.epoll.EpollServerSocketChannel; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.channel.socket.SocketChannel; +import io.netty.channel.socket.nio.NioServerSocketChannel; +import io.netty.handler.codec.protobuf.ProtobufDecoder; +import io.netty.handler.codec.protobuf.ProtobufEncoder; +import io.netty.handler.codec.protobuf.ProtobufVarint32FrameDecoder; +import io.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender; +import io.netty.handler.timeout.IdleStateHandler; +import org.nico.ratel.landlords.entity.ServerTransferData; +import org.nico.ratel.landlords.print.SimplePrinter; +import org.nico.ratel.landlords.robot.RobotDecisionMakers; +import org.nico.ratel.landlords.server.ServerContains; +import org.nico.ratel.landlords.server.handler.SecondProtobufCodec; +import org.nico.ratel.landlords.server.handler.ProtobufTransferHandler; +import org.nico.ratel.landlords.server.timer.RoomClearTask; + +import java.net.InetSocketAddress; +import java.util.Timer; +import java.util.concurrent.TimeUnit; + +public class ProtobufProxy implements Proxy{ + @Override + public void start(int port) throws InterruptedException { + EventLoopGroup parentGroup = Epoll.isAvailable() ? new EpollEventLoopGroup() : new NioEventLoopGroup(); + EventLoopGroup childGroup = Epoll.isAvailable() ? new EpollEventLoopGroup() : new NioEventLoopGroup(); + try { + ServerBootstrap bootstrap = new ServerBootstrap() + .group(parentGroup, childGroup) + .channel(Epoll.isAvailable() ? EpollServerSocketChannel.class : NioServerSocketChannel.class) + .localAddress(new InetSocketAddress(port)) + .childHandler(new ChannelInitializer() { + @Override + protected void initChannel(SocketChannel ch) throws Exception { + ch.pipeline() + .addLast(new IdleStateHandler(60 * 30, 0, 0, TimeUnit.SECONDS)) + .addLast(new ProtobufVarint32FrameDecoder()) + .addLast(new ProtobufDecoder(ServerTransferData.ServerTransferDataProtoc.getDefaultInstance())) + .addLast(new ProtobufVarint32LengthFieldPrepender()) + .addLast(new ProtobufEncoder()) + .addLast(new SecondProtobufCodec()) + .addLast(new ProtobufTransferHandler()); + } + }); + + ChannelFuture f = bootstrap .bind().sync(); + + SimplePrinter.serverLog("The protobuf server was successfully started on port " + port); + //Init robot. + RobotDecisionMakers.init(); + + ServerContains.THREAD_EXCUTER.execute(() -> { + Timer timer=new Timer(); + timer.schedule(new RoomClearTask(), 0L, 3000L); + }); + f.channel().closeFuture().sync(); + } finally { + parentGroup.shutdownGracefully(); + childGroup.shutdownGracefully(); + } + + } +} diff --git a/landlords-server/src/main/java/org/nico/ratel/landlords/server/proxy/Proxy.java b/landlords-server/src/main/java/org/nico/ratel/landlords/server/proxy/Proxy.java new file mode 100644 index 0000000..98d021e --- /dev/null +++ b/landlords-server/src/main/java/org/nico/ratel/landlords/server/proxy/Proxy.java @@ -0,0 +1,7 @@ +package org.nico.ratel.landlords.server.proxy; + +public interface Proxy { + + void start(int port) throws InterruptedException; + +} diff --git a/landlords-server/src/main/java/org/nico/ratel/landlords/server/proxy/WebsocketProxy.java b/landlords-server/src/main/java/org/nico/ratel/landlords/server/proxy/WebsocketProxy.java new file mode 100644 index 0000000..ce4fa75 --- /dev/null +++ b/landlords-server/src/main/java/org/nico/ratel/landlords/server/proxy/WebsocketProxy.java @@ -0,0 +1,64 @@ +package org.nico.ratel.landlords.server.proxy; + +import io.netty.bootstrap.ServerBootstrap; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelInitializer; +import io.netty.channel.EventLoopGroup; +import io.netty.channel.epoll.Epoll; +import io.netty.channel.epoll.EpollEventLoopGroup; +import io.netty.channel.epoll.EpollServerSocketChannel; +import io.netty.channel.nio.NioEventLoopGroup; +import io.netty.channel.socket.SocketChannel; +import io.netty.channel.socket.nio.NioServerSocketChannel; +import io.netty.handler.codec.http.HttpObjectAggregator; +import io.netty.handler.codec.http.HttpServerCodec; +import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler; +import io.netty.handler.stream.ChunkedWriteHandler; +import io.netty.handler.timeout.IdleStateHandler; +import org.nico.ratel.landlords.print.SimplePrinter; +import org.nico.ratel.landlords.robot.RobotDecisionMakers; +import org.nico.ratel.landlords.server.ServerContains; +import org.nico.ratel.landlords.server.handler.ProtobufTransferHandler; +import org.nico.ratel.landlords.server.handler.WebsocketTransferHandler; +import org.nico.ratel.landlords.server.timer.RoomClearTask; + +import java.net.InetSocketAddress; +import java.util.Timer; +import java.util.concurrent.TimeUnit; + +public class WebsocketProxy implements Proxy{ + @Override + public void start(int port) throws InterruptedException { + EventLoopGroup parentGroup = Epoll.isAvailable() ? new EpollEventLoopGroup() : new NioEventLoopGroup(); + EventLoopGroup childGroup = Epoll.isAvailable() ? new EpollEventLoopGroup() : new NioEventLoopGroup(); + try { + ServerBootstrap bootstrap = new ServerBootstrap() + .group(parentGroup, childGroup) + .channel(Epoll.isAvailable() ? EpollServerSocketChannel.class : NioServerSocketChannel.class) + .localAddress(new InetSocketAddress(port)) + .childHandler(new ChannelInitializer() { + @Override + protected void initChannel(SocketChannel ch) throws Exception { + ch.pipeline() + .addLast(new IdleStateHandler(60 * 30, 0, 0, TimeUnit.SECONDS)) + .addLast(new HttpServerCodec()) + .addLast(new ChunkedWriteHandler()) + .addLast(new HttpObjectAggregator(8192)) + .addLast("ws", new WebSocketServerProtocolHandler("/ratel")) + .addLast(new WebsocketTransferHandler()); + } + }); + + ChannelFuture f = bootstrap .bind().sync(); + + SimplePrinter.serverLog("The websocket server was successfully started on port " + port); + //Init robot. + RobotDecisionMakers.init(); + f.channel().closeFuture().sync(); + } finally { + parentGroup.shutdownGracefully(); + childGroup.shutdownGracefully(); + } + + } +} diff --git a/landlords-server/src/main/java/org/nico/ratel/landlords/server/robot/RobotEventListener.java b/landlords-server/src/main/java/org/nico/ratel/landlords/server/robot/RobotEventListener.java new file mode 100644 index 0000000..3985452 --- /dev/null +++ b/landlords-server/src/main/java/org/nico/ratel/landlords/server/robot/RobotEventListener.java @@ -0,0 +1,40 @@ +package org.nico.ratel.landlords.server.robot; + +import java.lang.reflect.InvocationTargetException; +import java.util.HashMap; +import java.util.Map; + +import org.nico.ratel.landlords.entity.ClientSide; +import org.nico.ratel.landlords.enums.ClientEventCode; + +public interface RobotEventListener { + + String LISTENER_PREFIX = "org.nico.ratel.landlords.server.robot.RobotEventListener_"; + + Map LISTENER_MAP = new HashMap<>(); + + void call(ClientSide robot, String data); + + @SuppressWarnings("unchecked") + static RobotEventListener get(ClientEventCode code) { + RobotEventListener listener = null; + try { + if (RobotEventListener.LISTENER_MAP.containsKey(code)) { + listener = RobotEventListener.LISTENER_MAP.get(code); + } else { + String eventListener = LISTENER_PREFIX + code.name(); + Class listenerClass = (Class) Class.forName(eventListener); + try { + listener = listenerClass.getDeclaredConstructor().newInstance(); + } catch (NoSuchMethodException | InvocationTargetException e) { + e.printStackTrace(); + } + RobotEventListener.LISTENER_MAP.put(code, listener); + } + return listener; + } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) { + e.printStackTrace(); + } + return null; + } +} diff --git a/landlords-server/src/main/java/org/nico/ratel/landlords/server/robot/RobotEventListener_CODE_GAME_LANDLORD_ELECT.java b/landlords-server/src/main/java/org/nico/ratel/landlords/server/robot/RobotEventListener_CODE_GAME_LANDLORD_ELECT.java new file mode 100644 index 0000000..73ea3c5 --- /dev/null +++ b/landlords-server/src/main/java/org/nico/ratel/landlords/server/robot/RobotEventListener_CODE_GAME_LANDLORD_ELECT.java @@ -0,0 +1,43 @@ +package org.nico.ratel.landlords.server.robot; + +import java.util.ArrayList; +import java.util.List; + +import org.nico.ratel.landlords.entity.ClientSide; +import org.nico.ratel.landlords.entity.Poker; +import org.nico.ratel.landlords.entity.Room; +import org.nico.ratel.landlords.enums.ServerEventCode; +import org.nico.ratel.landlords.helper.PokerHelper; +import org.nico.ratel.landlords.helper.TimeHelper; +import org.nico.ratel.landlords.robot.RobotDecisionMakers; +import org.nico.ratel.landlords.server.ServerContains; +import org.nico.ratel.landlords.server.event.ServerEventListener; + +public class RobotEventListener_CODE_GAME_LANDLORD_ELECT implements RobotEventListener { + + @Override + public void call(ClientSide robot, String data) { + ServerContains.THREAD_EXCUTER.execute(() -> { + Room room = ServerContains.getRoom(robot.getRoomId()); + + List landlordPokers = new ArrayList<>(20); + landlordPokers.addAll(robot.getPokers()); + landlordPokers.addAll(room.getLandlordPokers()); + + List leftPokers = new ArrayList<>(17); + leftPokers.addAll(robot.getPre().getPokers()); + + List rightPokers = new ArrayList<>(17); + rightPokers.addAll(robot.getNext().getPokers()); + + PokerHelper.sortPoker(landlordPokers); + PokerHelper.sortPoker(leftPokers); + PokerHelper.sortPoker(rightPokers); + + TimeHelper.sleep(300); + + ServerEventListener.get(ServerEventCode.CODE_GAME_LANDLORD_ELECT).call(robot, String.valueOf(RobotDecisionMakers.howToChooseLandlord(room.getDifficultyCoefficient(), leftPokers, rightPokers, landlordPokers))); + }); + } + +} diff --git a/landlords-server/src/main/java/org/nico/ratel/landlords/server/robot/RobotEventListener_CODE_GAME_POKER_PLAY.java b/landlords-server/src/main/java/org/nico/ratel/landlords/server/robot/RobotEventListener_CODE_GAME_POKER_PLAY.java new file mode 100644 index 0000000..7a98f92 --- /dev/null +++ b/landlords-server/src/main/java/org/nico/ratel/landlords/server/robot/RobotEventListener_CODE_GAME_POKER_PLAY.java @@ -0,0 +1,52 @@ +package org.nico.ratel.landlords.server.robot; + +import org.nico.noson.Noson; +import org.nico.ratel.landlords.entity.ClientSide; +import org.nico.ratel.landlords.entity.PokerSell; +import org.nico.ratel.landlords.entity.Room; +import org.nico.ratel.landlords.enums.SellType; +import org.nico.ratel.landlords.enums.ServerEventCode; +import org.nico.ratel.landlords.helper.PokerHelper; +import org.nico.ratel.landlords.helper.TimeHelper; +import org.nico.ratel.landlords.print.SimplePrinter; +import org.nico.ratel.landlords.robot.RobotDecisionMakers; +import org.nico.ratel.landlords.server.ServerContains; +import org.nico.ratel.landlords.server.event.ServerEventListener; + +public class RobotEventListener_CODE_GAME_POKER_PLAY implements RobotEventListener { + + @Override + public void call(ClientSide robot, String data) { + ServerContains.THREAD_EXCUTER.execute(() -> { + Room room = ServerContains.getRoom(robot.getRoomId()); + + PokerSell lastPokerSell = null; + PokerSell pokerSell = null; + if (room.getLastSellClient() != robot.getId()) { + lastPokerSell = room.getLastPokerShell(); + pokerSell = RobotDecisionMakers.howToPlayPokers(room.getDifficultyCoefficient(), lastPokerSell, robot); + } else { + pokerSell = RobotDecisionMakers.howToPlayPokers(room.getDifficultyCoefficient(), null, robot); + } + + if (pokerSell != null && lastPokerSell != null) { + SimplePrinter.serverLog("Robot monitoring[room:" + room.getId() + "]"); + SimplePrinter.serverLog("last sell -> " + lastPokerSell.toString()); + SimplePrinter.serverLog("robot sell -> " + pokerSell.toString()); + SimplePrinter.serverLog("robot poker -> " + PokerHelper.textOnlyNoType(robot.getPokers())); + } + + TimeHelper.sleep(300); + + if (pokerSell == null || pokerSell.getSellType() == SellType.ILLEGAL) { + ServerEventListener.get(ServerEventCode.CODE_GAME_POKER_PLAY_PASS).call(robot, data); + } else { + Character[] cs = new Character[pokerSell.getSellPokers().size()]; + for (int index = 0; index < cs.length; index++) { + cs[index] = pokerSell.getSellPokers().get(index).getLevel().getAlias()[0]; + } + ServerEventListener.get(ServerEventCode.CODE_GAME_POKER_PLAY).call(robot, Noson.reversal(cs)); + } + }); + } +} diff --git a/landlords-server/src/main/java/org/nico/ratel/landlords/server/timer/RoomClearTask.java b/landlords-server/src/main/java/org/nico/ratel/landlords/server/timer/RoomClearTask.java new file mode 100644 index 0000000..4fa4edb --- /dev/null +++ b/landlords-server/src/main/java/org/nico/ratel/landlords/server/timer/RoomClearTask.java @@ -0,0 +1,145 @@ +package org.nico.ratel.landlords.server.timer; + +import java.util.Map; +import java.util.TimerTask; + +import org.nico.ratel.landlords.channel.ChannelUtils; +import org.nico.ratel.landlords.entity.ClientSide; +import org.nico.ratel.landlords.entity.Room; +import org.nico.ratel.landlords.enums.ClientEventCode; +import org.nico.ratel.landlords.enums.ClientRole; +import org.nico.ratel.landlords.enums.ClientStatus; +import org.nico.ratel.landlords.enums.RoomStatus; +import org.nico.ratel.landlords.enums.RoomType; +import org.nico.ratel.landlords.enums.ServerEventCode; +import org.nico.ratel.landlords.print.SimplePrinter; +import org.nico.ratel.landlords.server.ServerContains; +import org.nico.ratel.landlords.server.event.ServerEventListener; +import org.nico.ratel.landlords.server.robot.RobotEventListener; + +/** + * + * @author nico + */ + +public class RoomClearTask extends TimerTask { + + //The room wait time of after create is 100s + private static final long waitingStatusInterval = 1000 * 100; + + //The room starting destroy time is 100s + private static final long startingStatusInterval = 1000 * 300; + + //The room live time is 600s + private static final long liveTime = 1000 * 60 * 20; + + @Override + public void run() { + try { + doing(); + } catch (Exception e) { + SimplePrinter.serverLog(e.getMessage()); + } + + } + + public void doing() { + Map rooms = ServerContains.getRoomMap(); + if (rooms == null || rooms.isEmpty()) { + return; + } + + long now = System.currentTimeMillis(); + for (Room room : rooms.values()) { + long alreadyLiveTime = System.currentTimeMillis() - room.getCreateTime(); + SimplePrinter.serverLog("room " + room.getId() + " already live " + alreadyLiveTime + "ms"); + if (alreadyLiveTime > liveTime) { + SimplePrinter.serverLog("room " + room.getId() + " live time overflow " + liveTime + ", closed!"); + ServerEventListener.get(ServerEventCode.CODE_CLIENT_EXIT).call(room.getClientSideList().get(0), null); + continue; + } + + long diff = now - room.getLastFlushTime(); + if (room.getStatus() != RoomStatus.STARTING && diff > waitingStatusInterval) { + SimplePrinter.serverLog("room " + room.getId() + " starting waiting time overflow " + waitingStatusInterval + ", closed!"); + ServerEventListener.get(ServerEventCode.CODE_CLIENT_EXIT).call(room.getClientSideList().get(0), null); + continue; + } + if (room.getType() != RoomType.PVP) { + continue; + } + + if (diff <= startingStatusInterval) { + continue; + } + + boolean allRobots = true; + for (ClientSide client : room.getClientSideList()) { + if (client.getId() != room.getCurrentSellClient() && client.getRole() == ClientRole.PLAYER) { + allRobots = false; + break; + } + } + + ClientSide currentPlayer = room.getClientSideMap().get(room.getCurrentSellClient()); + + if (allRobots) { + SimplePrinter.serverLog("room " + room.getId() + " all is robots, closed!"); + ServerEventListener.get(ServerEventCode.CODE_CLIENT_EXIT).call(currentPlayer, null); + continue; + } + //kick this client + ChannelUtils.pushToClient(currentPlayer.getChannel(), ClientEventCode.CODE_CLIENT_KICK, null); + + notifyWatcherClientKick(room, currentPlayer); + + //client current player + room.getClientSideMap().remove(currentPlayer.getId()); + room.getClientSideList().remove(currentPlayer); + + ClientSide robot = new ClientSide(-ServerContains.getClientId(), ClientStatus.PLAYING, null); + robot.setNickname(currentPlayer.getNickname()); + robot.setRole(ClientRole.ROBOT); + robot.setRoomId(room.getId()); + robot.setNext(currentPlayer.getNext()); + robot.setPre(currentPlayer.getPre()); + robot.getNext().setPre(robot); + robot.getPre().setNext(robot); + robot.setPokers(currentPlayer.getPokers()); + robot.setType(currentPlayer.getType()); + + room.getClientSideMap().put(robot.getId(), robot); + room.getClientSideList().add(robot); + room.setCurrentSellClient(robot.getId()); + + //If last sell client is current client, replace it to robot id + if (room.getLastSellClient() == currentPlayer.getId()) { + room.setLastSellClient(robot.getId()); + } + + //set robot difficulty -> simple + room.setDifficultyCoefficient(1); + + ServerContains.CLIENT_SIDE_MAP.put(robot.getId(), robot); + + //init client + currentPlayer.init(); + + SimplePrinter.serverLog("room " + room.getId() + " player " + currentPlayer.getNickname() + " " + startingStatusInterval + "ms not operating, automatic custody!"); + + RobotEventListener.get(room.getLandlordId() == -1 ? ClientEventCode.CODE_GAME_LANDLORD_ELECT : ClientEventCode.CODE_GAME_POKER_PLAY).call(robot, null); + } + } + + /** + * 通知观战者玩家被提出房间 + * + * @param room 房间 + * @param player 被提出的玩家 + */ + private void notifyWatcherClientKick(Room room, ClientSide player) { + for (ClientSide watcher : room.getWatcherList()) { + ChannelUtils.pushToClient(watcher.getChannel(), ClientEventCode.CODE_CLIENT_KICK, player.getNickname()); + } + } +} diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..a43e81b --- /dev/null +++ b/pom.xml @@ -0,0 +1,97 @@ + + 4.0.0 + com.smallnico.ratel + landlords + 1.4.0 + ratel + https://github.com/ainilili/ratel + pom + Ratel Project + + + 1.8 + 1.8 + UTF-8 + + 2.0.5.RELEASE + 1.0.7 + 1.0.7 + ${java.compiler.argument} + + + + org.springframework.boot + spring-boot-starters + 2.0.5.RELEASE + + + + + io.netty + netty-all + + + com.google.protobuf + protobuf-java + 3.16.1 + + + com.smallnico + noson + 1.1.6 + + + com.google.code.gson + gson + + + junit + junit + test + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.1 + + ${java.version.source} + ${java.version.target} + ${java.compiler.argument} + ${java.specification.version} + ${java.specification.version} + ${java.test.compiler.argument} + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + + org.apache.maven.plugins + maven-source-plugin + + + org.apache.maven.plugins + maven-javadoc-plugin + + + + + + landlords-client + landlords-server + landlords-common + + + + diff --git a/protoc-resource/ClientTransferDataProtoc.proto b/protoc-resource/ClientTransferDataProtoc.proto new file mode 100644 index 0000000..4504523 --- /dev/null +++ b/protoc-resource/ClientTransferDataProtoc.proto @@ -0,0 +1,15 @@ +syntax = "proto3"; + +package org.nico.ratel.landlords.entity; + +option java_package = "org.nico.ratel.landlords.entity"; +option java_outer_classname = "ClientTransferData"; + +message ClientTransferDataProtoc{ + + string code = 1; + + string data = 2; + + string info = 3; +} \ No newline at end of file diff --git a/protoc-resource/ServerTransferDataProtoc.proto b/protoc-resource/ServerTransferDataProtoc.proto new file mode 100644 index 0000000..27a59d0 --- /dev/null +++ b/protoc-resource/ServerTransferDataProtoc.proto @@ -0,0 +1,15 @@ +syntax = "proto3"; + +package org.nico.ratel.landlords.entity; + +option java_package = "org.nico.ratel.landlords.entity"; +option java_outer_classname = "ServerTransferData"; + +message ServerTransferDataProtoc{ + + string code = 1; + + string data = 2; + + string info = 3; +} \ No newline at end of file diff --git a/protoc-resource/generate.sh b/protoc-resource/generate.sh new file mode 100644 index 0000000..17f107e --- /dev/null +++ b/protoc-resource/generate.sh @@ -0,0 +1 @@ +protoc -I=. --java_out=../landlords-common/src/main/java/ ./*.proto \ No newline at end of file diff --git a/serverlist.json b/serverlist.json new file mode 100644 index 0000000..52a7cb3 --- /dev/null +++ b/serverlist.json @@ -0,0 +1,8 @@ +[ + "49.235.95.125:1024:Nico[v1.4.0]", + "47.103.16.48:1024:jsClient[v1.2.7]", + "s2.imlazy.ink:25020:FxCraft[v1.2.6]", + "47.240.60.124:6565:ChenCodeX[v1.2.6]", + "cmi.zerodream.net:1919:ZeroDream[v1.2.2]", + "106.14.125.226:1024:jipaiqi[v1.4.0]" +]