Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
N
Neos
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Locked Files
Issues
1
Issues
1
List
Boards
Labels
Service Desk
Milestones
Merge Requests
2
Merge Requests
2
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Security & Compliance
Security & Compliance
Dependency List
License Compliance
Packages
Packages
List
Container Registry
Analytics
Analytics
CI / CD
Code Review
Insights
Issues
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
MyCard
Neos
Commits
1c2804f4
Commit
1c2804f4
authored
Oct 29, 2022
by
Chunchi Che
Committed by
WANG HE
Dec 23, 2022
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
add comment
parent
029a83e5
Changes
27
Hide whitespace changes
Inline
Side-by-side
Showing
27 changed files
with
194 additions
and
6 deletions
+194
-6
src/api/Card.ts
src/api/Card.ts
+7
-0
src/api/ocgcore/ocgAdapter/adapter.ts
src/api/ocgcore/ocgAdapter/adapter.ts
+8
-1
src/api/ocgcore/ocgAdapter/ctos/ctosHsReady.ts
src/api/ocgcore/ocgAdapter/ctos/ctosHsReady.ts
+5
-0
src/api/ocgcore/ocgAdapter/ctos/ctosHsStart.ts
src/api/ocgcore/ocgAdapter/ctos/ctosHsStart.ts
+5
-0
src/api/ocgcore/ocgAdapter/ctos/ctosJoinGame.ts
src/api/ocgcore/ocgAdapter/ctos/ctosJoinGame.ts
+10
-0
src/api/ocgcore/ocgAdapter/ctos/ctosPlayerInfo.ts
src/api/ocgcore/ocgAdapter/ctos/ctosPlayerInfo.ts
+7
-0
src/api/ocgcore/ocgAdapter/ctos/ctosUpdateDeck.ts
src/api/ocgcore/ocgAdapter/ctos/ctosUpdateDeck.ts
+12
-0
src/api/ocgcore/ocgAdapter/packet.ts
src/api/ocgcore/ocgAdapter/packet.ts
+18
-3
src/api/ocgcore/ocgAdapter/protoDecl.ts
src/api/ocgcore/ocgAdapter/protoDecl.ts
+4
-0
src/api/ocgcore/ocgAdapter/stoc/stocChat.ts
src/api/ocgcore/ocgAdapter/stoc/stocChat.ts
+8
-0
src/api/ocgcore/ocgAdapter/stoc/stocHsPlayerChange.ts
src/api/ocgcore/ocgAdapter/stoc/stocHsPlayerChange.ts
+7
-0
src/api/ocgcore/ocgAdapter/stoc/stocHsPlayerEnter.ts
src/api/ocgcore/ocgAdapter/stoc/stocHsPlayerEnter.ts
+8
-0
src/api/ocgcore/ocgAdapter/stoc/stocHsWatchChange.ts
src/api/ocgcore/ocgAdapter/stoc/stocHsWatchChange.ts
+7
-0
src/api/ocgcore/ocgAdapter/stoc/stocJoinGame.ts
src/api/ocgcore/ocgAdapter/stoc/stocJoinGame.ts
+5
-0
src/api/ocgcore/ocgAdapter/stoc/stocTypeChange.ts
src/api/ocgcore/ocgAdapter/stoc/stocTypeChange.ts
+7
-0
src/api/ocgcore/ocgAdapter/util.ts
src/api/ocgcore/ocgAdapter/util.ts
+11
-0
src/api/ocgcore/ocgHelper.ts
src/api/ocgcore/ocgHelper.ts
+6
-2
src/middleware/socket.ts
src/middleware/socket.ts
+12
-0
src/reducers/chatSlice.ts
src/reducers/chatSlice.ts
+4
-0
src/reducers/joinSlice.ts
src/reducers/joinSlice.ts
+4
-0
src/reducers/playerSlice.ts
src/reducers/playerSlice.ts
+4
-0
src/service/onSocketMessage.ts
src/service/onSocketMessage.ts
+9
-0
src/service/onSocketOpen.ts
src/service/onSocketOpen.ts
+9
-0
src/store.ts
src/store.ts
+3
-0
src/ui/BabylonJs.tsx
src/ui/BabylonJs.tsx
+1
-0
src/ui/JoinRoom.tsx
src/ui/JoinRoom.tsx
+8
-0
src/ui/WaitRoom.tsx
src/ui/WaitRoom.tsx
+5
-0
No files found.
src/api/Card.ts
View file @
1c2804f4
...
...
@@ -6,6 +6,13 @@ export interface IDeck {
side
?:
number
[];
}
/*
* 返回卡组资源。
*
* @param deck- 卡组名称
* @returns 卡组数据
*
* */
export
async
function
fetchDeck
(
deck
:
string
):
Promise
<
IDeck
>
{
const
res
=
await
axios
.
get
<
IDeck
>
(
"
http://localhost:3030/deck/
"
+
deck
);
...
...
src/api/ocgcore/ocgAdapter/adapter.ts
View file @
1c2804f4
import
{
StocAdapter
,
ygoProPacket
}
from
"
./packet
"
;
import
{
ygoProPacket
}
from
"
./packet
"
;
import
{
ygopro
}
from
"
../idl/ocgcore
"
;
import
{
STOC_CHAT
,
...
...
@@ -15,6 +15,13 @@ import StocHsPlayerChange from "./stoc/stocHsPlayerChange";
import
StocHsWatchChange
from
"
./stoc/stocHsWatchChange
"
;
import
StocTypeChange
from
"
./stoc/stocTypeChange
"
;
/*
* 将[`ygoProPacket`]对象转换成[`ygopro.YgoStocMsg`]对象
*
* @param packet - The ygoProPacket object
* @returns The ygopro.YgoStocMsg object
*
* */
export
function
adaptStoc
(
packet
:
ygoProPacket
):
ygopro
.
YgoStocMsg
{
let
pb
=
new
ygopro
.
YgoStocMsg
({});
switch
(
packet
.
proto
)
{
...
...
src/api/ocgcore/ocgAdapter/ctos/ctosHsReady.ts
View file @
1c2804f4
...
...
@@ -2,6 +2,11 @@ import { ygopro } from "../../idl/ocgcore";
import
{
ygoProPacket
}
from
"
../packet
"
;
import
{
CTOS_HS_READY
}
from
"
../protoDecl
"
;
/*
* CTOS HsReady
*
* @usage - 告诉ygopro服务端当前玩家准备完毕
* */
export
default
class
CtosHsReady
extends
ygoProPacket
{
constructor
(
_
:
ygopro
.
YgoCtosMsg
)
{
super
(
1
,
CTOS_HS_READY
,
new
Uint8Array
(
0
));
...
...
src/api/ocgcore/ocgAdapter/ctos/ctosHsStart.ts
View file @
1c2804f4
...
...
@@ -2,6 +2,11 @@ import { ygopro } from "../../idl/ocgcore";
import
{
ygoProPacket
}
from
"
../packet
"
;
import
{
CTOS_HS_START
}
from
"
../protoDecl
"
;
/*
* CTOS HsStart
*
* @usage - 开始游戏对局
* */
export
default
class
CtosHsStartPacket
extends
ygoProPacket
{
constructor
(
_
:
ygopro
.
YgoCtosMsg
)
{
super
(
1
,
CTOS_HS_START
,
new
Uint8Array
(
0
));
...
...
src/api/ocgcore/ocgAdapter/ctos/ctosJoinGame.ts
View file @
1c2804f4
...
...
@@ -3,6 +3,16 @@ import { ygoProPacket } from "../packet";
import
{
CTOS_JOIN_GAME
}
from
"
../protoDecl
"
;
import
{
strEncodeUTF16
}
from
"
../util
"
;
/*
* CTOS JoinGame
*
* @param version: unsigned short - 版本号
* @param align: unsigned short - 对齐填充
* @param gameid: unsigned int - 永远是0
* @param passWd: [unsigned short; 20] - 房间密码
*
* @usage - 加入房间
* */
export
default
class
CtosJoinGamePacket
extends
ygoProPacket
{
constructor
(
pb
:
ygopro
.
YgoCtosMsg
)
{
const
joinGame
=
pb
.
ctos_join_game
;
...
...
src/api/ocgcore/ocgAdapter/ctos/ctosPlayerInfo.ts
View file @
1c2804f4
...
...
@@ -3,6 +3,13 @@ import { ygoProPacket } from "../packet";
import
{
CTOS_PLAYER_INFO
}
from
"
../protoDecl
"
;
import
{
strEncodeUTF16
}
from
"
../util
"
;
/*
* CTOS PlayerInfo
*
* @param player: [unsigned short; 20] - 玩家昵称
*
* @usage - 告诉ygopro服务端当前玩家的昵称
* */
export
default
class
CtosPlayerInfoPacket
extends
ygoProPacket
{
constructor
(
pb
:
ygopro
.
YgoCtosMsg
)
{
const
player
=
pb
.
ctos_player_info
.
name
;
...
...
src/api/ocgcore/ocgAdapter/ctos/ctosUpdateDeck.ts
View file @
1c2804f4
...
...
@@ -4,6 +4,18 @@ import { CTOS_UPDATE_DECK } from "../protoDecl";
const
BYTES_PER_U32
=
4
;
/*
* CTOS UpdateDeck
*
* @param main: unsigned int - 主卡组数目
* @param extra: unsigned int - 额外卡组数目
* @param side: unsigned int - 副卡组数目
* @param mainCards: [unsigned int; main] - 主卡组数据
* @param extraCards: [unsigned int; extra] - 额外卡组数据
* @param side: [unsigned int; side] - 副卡组数据
*
* @usage - 更新对局的卡组信息
* */
export
default
class
CtosUpdateDeck
extends
ygoProPacket
{
constructor
(
pb
:
ygopro
.
YgoCtosMsg
)
{
const
updateDeck
=
pb
.
ctos_update_deck
;
...
...
src/api/ocgcore/ocgAdapter/packet.ts
View file @
1c2804f4
/*
* Adapter模块的抽象层。
*
* */
import
{
ygopro
}
from
"
../idl/ocgcore
"
;
const
littleEndian
:
boolean
=
true
;
const
PACKET_MIN_LEN
=
3
;
// Ref: https://www.icode9.com/content-1-1341344.html
export
class
ygoProPacket
{
packetLen
:
number
;
proto
:
number
;
exData
:
Uint8Array
;
packetLen
:
number
;
// 数据包长度
proto
:
number
;
// ygopro协议标识
exData
:
Uint8Array
;
// 数据包内容
constructor
(
packetLen
:
number
,
proto
:
number
,
exData
:
Uint8Array
)
{
this
.
packetLen
=
packetLen
;
...
...
@@ -14,6 +19,11 @@ export class ygoProPacket {
this
.
exData
=
exData
;
}
/*
* 将[`ygoProPacket`]对象序列化,
* 返回的二进制数数组可通过长连接发送到ygopro服务端。
*
* */
serialize
():
Uint8Array
{
const
array
=
new
Uint8Array
(
this
.
packetLen
+
2
);
const
dataView
=
new
DataView
(
array
.
buffer
);
...
...
@@ -25,6 +35,11 @@ export class ygoProPacket {
return
array
;
}
/*
* 将二进制数据反序列化成[`ygoProPacket`]对象,
* 返回值可用于业务逻辑处理。
*
* */
static
deserialize
(
array
:
ArrayBuffer
):
ygoProPacket
{
try
{
if
(
array
.
byteLength
<
PACKET_MIN_LEN
)
{
...
...
src/api/ocgcore/ocgAdapter/protoDecl.ts
View file @
1c2804f4
/*
* Ygopro的协议标识声明。
*
* */
export
const
CTOS_PLAYER_INFO
=
16
;
export
const
CTOS_JOIN_GAME
=
18
;
export
const
CTOS_UPDATE_DECK
=
2
;
...
...
src/api/ocgcore/ocgAdapter/stoc/stocChat.ts
View file @
1c2804f4
import
{
ygopro
}
from
"
../../idl/ocgcore
"
;
import
{
ygoProPacket
,
StocAdapter
}
from
"
../packet
"
;
/*
* STOC Chat
*
* @param player: unsigned short - 玩家编号
* @param message: [unsigned short] - 聊天消息文本
*
* @usage - 更新聊天消息
* */
export
default
class
chatAdapter
implements
StocAdapter
{
packet
:
ygoProPacket
;
...
...
src/api/ocgcore/ocgAdapter/stoc/stocHsPlayerChange.ts
View file @
1c2804f4
import
{
ygopro
}
from
"
../../idl/ocgcore
"
;
import
{
ygoProPacket
,
StocAdapter
}
from
"
../packet
"
;
/*
* STOC HsPlayerChange
*
* @param todo
*
* @usage - 更新玩家状态
* */
export
default
class
hsPlayerChangeAdapter
implements
StocAdapter
{
packet
:
ygoProPacket
;
...
...
src/api/ocgcore/ocgAdapter/stoc/stocHsPlayerEnter.ts
View file @
1c2804f4
...
...
@@ -4,6 +4,14 @@ import { UTF16_BUFFER_MAX_LEN } from "../util";
const
UINT8_PER_UINT16
=
2
;
/*
* STOC HsPlayerEnter
*
* @param name: [unsigned short; 20] - 玩家昵称
* @param pos: unsigned chat - 玩家进入房间的位置
*
* @usage - 有新玩家进入房间,更新状态
* */
export
default
class
hsPlayerEnterAdapter
implements
StocAdapter
{
packet
:
ygoProPacket
;
...
...
src/api/ocgcore/ocgAdapter/stoc/stocHsWatchChange.ts
View file @
1c2804f4
import
{
ygopro
}
from
"
../../idl/ocgcore
"
;
import
{
ygoProPacket
,
StocAdapter
}
from
"
../packet
"
;
/*
* STOC HsWatchChange
*
* @param count: unsigned short - 观观者数量
*
* @usage - 更新观战者数量
* */
export
default
class
hsWatchChangeAdapter
implements
StocAdapter
{
packet
:
ygoProPacket
;
...
...
src/api/ocgcore/ocgAdapter/stoc/stocJoinGame.ts
View file @
1c2804f4
import
{
ygopro
}
from
"
../../idl/ocgcore
"
;
import
{
ygoProPacket
,
StocAdapter
}
from
"
../packet
"
;
/*
* STOC JoinGame
*
* @usage - 告知客户端/前端已成功加入房间
* */
export
default
class
joinGameAdapter
implements
StocAdapter
{
packet
:
ygoProPacket
;
...
...
src/api/ocgcore/ocgAdapter/stoc/stocTypeChange.ts
View file @
1c2804f4
import
{
ygopro
}
from
"
../../idl/ocgcore
"
;
import
{
ygoProPacket
,
StocAdapter
}
from
"
../packet
"
;
/*
* STOC TypeChange
*
* @param todo
*
* @usage - 更新玩家状态
* */
export
default
class
typeChangeAdapter
implements
StocAdapter
{
packet
:
ygoProPacket
;
...
...
src/api/ocgcore/ocgAdapter/util.ts
View file @
1c2804f4
/*
* 一些基础函数。
*
* */
export
const
UTF16_BUFFER_MAX_LEN
=
20
;
const
FILLING_TOKEN
:
number
=
0xcccc
;
/*
* 将`string`类型字符串转成`utf-16`编码的二进制数组。
*
* @param str - The `string` type string
* @returns The `utf-16` `Uint8Array`
*
* */
export
function
strEncodeUTF16
(
str
:
string
)
{
let
buf
=
new
ArrayBuffer
(
UTF16_BUFFER_MAX_LEN
*
2
);
let
bufView
=
new
Uint16Array
(
buf
);
...
...
src/api/ocgcore/ocgHelper.ts
View file @
1c2804f4
/*
* 一些发ygopro协议数据包的辅助函数,用于简化业务代码。
*
* */
import
{
ygopro
}
from
"
./idl/ocgcore
"
;
import
socketMiddleWare
,
{
socketCmd
}
from
"
../../middleware/socket
"
;
import
{
IDeck
}
from
"
../Card
"
;
...
...
@@ -16,7 +20,7 @@ export function sendUpdateDeck(deck: IDeck) {
}),
});
// 如果要实现UI层和Adapter层解耦,这里应该不感知具体Adapter类型
//
FIXME:
如果要实现UI层和Adapter层解耦,这里应该不感知具体Adapter类型
const
payload
=
new
UpdateDeckAdapter
(
updateDeck
).
serialize
();
socketMiddleWare
({
cmd
:
socketCmd
.
SEND
,
payload
});
...
...
@@ -46,7 +50,7 @@ export function sendPlayerInfo(ws: WebSocket, player: string) {
name
:
player
,
}),
});
const
packet
=
new
PlayerInfoAdapter
(
playerInfo
);
// todo: 需要收敛在一个层次里
const
packet
=
new
PlayerInfoAdapter
(
playerInfo
);
ws
.
send
(
packet
.
serialize
());
}
...
...
src/middleware/socket.ts
View file @
1c2804f4
/*
* Socket中间件
*
* 所有长连接/Websocket相关的逻辑都应该收敛在这里。
*
* */
import
handleSocketOpen
from
"
../service/onSocketOpen
"
;
import
handleSocketMessage
from
"
../service/onSocketMessage
"
;
export
enum
socketCmd
{
// 建立长连接
CONNECT
,
// 断开长连接
DISCONNECT
,
// 通过长连接发送数据
SEND
,
}
export
interface
socketAction
{
cmd
:
socketCmd
;
// 创建长连接需要业务方传入的数据
initInfo
?:
{
ip
:
string
;
player
:
string
;
passWd
:
string
;
};
// 通过长连接发送的数据
payload
?:
Uint8Array
;
}
let
ws
:
WebSocket
|
null
=
null
;
// FIXME: 应该有个返回值,告诉业务方本次请求的结果。比如建立长连接失败。
export
default
function
(
action
:
socketAction
)
{
switch
(
action
.
cmd
)
{
case
socketCmd
.
CONNECT
:
{
...
...
src/reducers/chatSlice.ts
View file @
1c2804f4
/*
* Chat状态更新逻辑
*
* */
import
{
createSlice
,
PayloadAction
}
from
"
@reduxjs/toolkit
"
;
import
{
RootState
}
from
"
../store
"
;
...
...
src/reducers/joinSlice.ts
View file @
1c2804f4
/*
* 加入房间状态更新逻辑
*
* */
import
{
createSlice
}
from
"
@reduxjs/toolkit
"
;
import
{
RootState
}
from
"
../store
"
;
...
...
src/reducers/playerSlice.ts
View file @
1c2804f4
/*
* 进入房间的玩家状态更新逻辑
*
* */
import
{
createSlice
,
PayloadAction
}
from
"
@reduxjs/toolkit
"
;
import
{
RootState
}
from
"
../store
"
;
...
...
src/service/onSocketMessage.ts
View file @
1c2804f4
/*
* 长连接消息事件订阅处理逻辑
*
* */
import
handleHsPlayerChange
from
"
./room/hsPlayerChange
"
;
import
handleTypeChange
from
"
./room/typeChange
"
;
import
handleHsPlayerEnter
from
"
./room/hsPlayerEnter
"
;
...
...
@@ -7,6 +11,11 @@ import handleHsWatchChange from "./room/hsWatchChange";
import
{
ygoProPacket
}
from
"
../api/ocgcore/ocgAdapter/packet
"
;
import
{
adaptStoc
}
from
"
../api/ocgcore/ocgAdapter/adapter
"
;
/*
* 先将从长连接中读取到的二进制数据通过Adapter转成protobuf结构体,
* 然后再分发到各个处理函数中去处理。
*
* */
export
default
function
handleSocketMessage
(
e
:
MessageEvent
)
{
const
packet
=
ygoProPacket
.
deserialize
(
e
.
data
);
const
pb
=
adaptStoc
(
packet
);
...
...
src/service/onSocketOpen.ts
View file @
1c2804f4
/*
* 长连接建立事件订阅处理逻辑
*
* */
import
{
sendJoinGame
,
sendPlayerInfo
}
from
"
../api/ocgcore/ocgHelper
"
;
/*
* 长连接建立后,需要马上发送PlayerInfo和JoinGame两个数据包,
* 否则ygopro服务端超过2s后会自动断连。
*
* */
export
default
function
handleSocketOpen
(
ws
:
WebSocket
|
null
,
ip
:
string
,
...
...
src/store.ts
View file @
1c2804f4
/*
* 全局状态存储模块
* */
import
{
configureStore
}
from
"
@reduxjs/toolkit
"
;
import
joinedReducer
from
"
./reducers/joinSlice
"
;
import
chatReducer
from
"
./reducers/chatSlice
"
;
...
...
src/ui/BabylonJs.tsx
View file @
1c2804f4
// 测试用的Babylon.js demo页面
import
React
,
{
useEffect
,
useRef
}
from
"
react
"
;
import
*
as
BABYLON
from
"
@babylonjs/core
"
;
...
...
src/ui/JoinRoom.tsx
View file @
1c2804f4
/*
* 加入房间页面
*
* player: 玩家昵称;
* addr: IP地址;
* passWd: 房间密码。
*
* */
import
React
,
{
useState
,
ChangeEvent
}
from
"
react
"
;
import
{
Link
}
from
"
react-router-dom
"
;
import
"
../css/JoinRoom.css
"
;
...
...
src/ui/WaitRoom.tsx
View file @
1c2804f4
/*
* 等待房间页面
*
* */
import
React
,
{
useEffect
,
useState
}
from
"
react
"
;
import
{
useParams
}
from
"
react-router-dom
"
;
import
{
fetchDeck
}
from
"
../api/Card
"
;
...
...
@@ -32,6 +36,7 @@ export default function WaitRoom() {
useEffect
(()
=>
{
if
(
ip
&&
player
&&
player
.
length
!=
0
&&
passWd
&&
passWd
.
length
!=
0
)
{
// 页面第一次渲染时,通过socket中间件向ygopro服务端请求建立长连接
socketMiddleWare
({
cmd
:
socketCmd
.
CONNECT
,
initInfo
:
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment