Modules for synchronizing with mvs synchronization server
- MVS API 문서
#initialize
sendPacket
#ReadProtocol
onReceivePacket
mvsUrl: string
mvsOrigin: string, masterUrl?: string, roomId?: number
shell
> @mv/mvs-sync@1.0.17 compile
> cd lib/utils/bufferProtocol && ./compile_pb.sh build
## ## ## ######
$3
#### #### ## ## ##
### ## ## ## ######
## ## ## ##
## ## ## ## ##
## ### ######
@mv/mvs-sync version 1.0.17
Generate by Protocol.proto completed.
Generate by Struct.proto completed.
Generate by Enum.proto completed.
`
- 변경된 프로토콜 적용 : npm run compile
- 컴파일된 프로토콜 삭제 : npm run compile clean
코드 위치 및 사용
- @mv/mvs-sync http://192.168.158.61/mv1/mvs/mvs-api-js
- Demo Client http://192.168.158.61/mv1/mvs/racing-test/-/tree/main
npm set registry http://192.168.154.143:4873/
npm i @mv/mvs-sync
MVS 분산환경 사용 시
`javascript
import {HeliosNetwork} from "@mv/mvs-sync/dist/utils/HeliosNetwork";
export const HSync = await HeliosNetwork.getInstance({
mode: 'cloud',
appKey: '8f9dfaba-1d6b-47e4-bb0c-966e0070f652'
})
`
$3
- HSync.CreateRoom() 또는 HSync.JoinRoom시 해당 룸 정보를 바탕으로 MV Master에서 적절한 MVS를 반환
지원 기능
- 룸 생성 및 입장, 룸 리스트, 유저 아이디 발급, 그룹 리스트, 그룹 입장
- 초기 객체 리스트, 객체 생성, 객체 파괴, 객체 동기화, 객체 소유권 이전 + RPC
- 사용 시나리오
1. 앱 생성 후 NameServer에서 REGION 등록
2. 앱 키를 환경변수로 등록하고 REGION을 명시 후 HeliosNetwork 객체 생성
3. 룸 리스트 조회
4. 원하는 룸 입장 또는 룸 생성
5. 그룹 리스트 조회
6. 원하는 그룹 입장 또는 그룹 생성
7. 씬의 상태 가져오기
8. 플레이어 아이디 요청
9. 오브젝트 생성
10. 생성한 오브젝트 동기화. 갱신 / 삭제 / 소유권 이전 등
클라이언트가 해야할 일
API 정상작동을 위해 해야할 일
1. mvs-auth-server에서 생성한 앱 키를 환경변수로 등록(REACT_APP_MVS_APP_KEY=APP_UUID)
2. MVS 분산환경 사용 시 REGION 정보를 NameServer에서 등록 후 인자로
3. 패킷 전송은 HeliosNetwork 에서, 오브젝트 관리는 MvsStore 에서
---
SyncManager 클래스에 다 포함되어 있습니다.
패키지 다운로드
npm set registry http://192.168.154.143:4873
npm i @mv/mvs-sync
HeliosSync.ts 파일 생성
`jsx
import {HeliosNetwork} from "@mv/mvs-sync/dist/utils/HeliosNetwork";
export const HSync = await HeliosNetwork.getInstance({
mode: 'cloud',
appKey: 'uuidv6-app-key'
})
`
웹팩 설정
웹팩 설정 해주셔야 사용 가능합니다
웹팩 설정
- 링크 들어가기 귀찮으시면 목차로 확인!
- mvs-sync는 Buffer를 사용하고 있어서 해당 플러그인을 추가해주셔야 합니다
- 순서대로 하시면 사용 가능하실 것으로 예상됩니다.
### 웹팩 override 라이브러리 설치
- npm install buffer process stream-browserify react-app-rewired
### scripts 수정
`json
"scripts" : {
"start": "react-app-rewired start",
"build": "react-app-rewired build",
"test": "react-app-rewired test",
"eject": "react-app-rewired eject"
},
`
### 설정 파일 생성
- root에 config-overrides.js 파일 생성
### 설정
`tsx
const webpack = require("webpack");
module.exports = function override(config, env) {
config.resolve.fallback = {
...config.resolve.fallback,
stream: require.resolve("stream-browserify"),
buffer: require.resolve("buffer"),
"querystring": false,
'process/browser': require.resolve('process/browser'), // 14:50 수정. mx 스튜디오에서 three js 랑 충돌나서 추가했습니다
};
config.resolve.alias = {
...config.resolve.alias,
ws: false,
};
config.resolve.extensions = [...config.resolve.extensions, ".ts", ".d.ts", ".js"];
config.plugins = [
...config.plugins,
new webpack.ProvidePlugin({
process: "process/browser",
Buffer: ["buffer", "Buffer"],
}),
];
return config;
};
`
Operation
- getState()
`tsx
import {HSync} from "../../mvs/HeliosSync";
// 현재 연결 상태 가져오기
expect(HSync.getState()).toEqual(ConnectState.ON_MVMASTER)
`
- Handler()
`tsx
import {HSync} from "../../mvs/HeliosSync";
// 동기화중인 MVS 정보 가져오기
const syncManager = HSync.Handler()
`
- HeartBeat()
`tsx
import {HSync} from "../../mvs/HeliosSync";
import {MvsStore} from "@mv/mvs-sync/dist/store/ObjectStateStore";
// MVS로 HeartBeat 패킷 보내기
HSync.HeartBeat()
const timestamp = MvsStore.healthCheck() // 패킷을 받은 시간
`
- async CreateRoom(params:RoomCreateParams)
`tsx
import {HSync} from "../../mvs/HeliosSync";
// MVS로 CreateRoom 패킷 보내기
HSync.InjectOnRoomJoinOrCreateHandler((message: S_ROOM_JOIN_OR_CREATE, sender?: PlayerInfo) => {
if (message.getResult() === Result.SUCCESS_ROOM_CREATE){
navigate(PathEnum.CANVAS)
}
else {
alert("Failed room join")
}
})
HSync.CreateRoom({
roomId: ROOMID,
appId: APPID,
authToken: "AUTHORIZATION_TOKEN",
name: ROOMNAME
})
`
- async JoinRoom(authToken:string, roomId:number)
`tsx
// MVS로 JoinRoom 패킷 보내기
HSync.InjectOnRoomJoinOrCreateHandler((message: S_ROOM_JOIN_OR_CREATE, sender?: PlayerInfo) => {
if (message.getResult() === Result.SUCCESS_ROOM_JOINED){
navigate(PathEnum.CANVAS)
}
else {
alert("Failed room join")
}
})
HSync.JoinRoom(
"AUTHORIZATION_TOKEN", ROOMID
)
`
- JoinGroup(params:GroupJoinParams)
`tsx
import {HSync} from "../../mvs/HeliosSync";
// MVS로 JoinGroup 패킷 보내기
HSync.JoinGroup({
scene: SCENE_NUMBER,
channel: CHANNEL_ID
})
`
- MvsRoomList()
`tsx
import {HSync} from "../../mvs/HeliosSync";
// MVS로 RoomList 패킷 보내기
HSync.RoomList().then((res)=>setRoomList(res));
HSync.Handler().onTestRoomListCustomHandler = (message) => {
const roomList = message.getRoominfosList()
}
`
- async RoomList()
`tsx
import {HSync} from "../../mvs/HeliosSync";
// MV Master 또는 MVS로 RoomList 패킷 보내기
HSync.RoomList().then((res)=>setRoomList(res));
`
- PlayerId()
`tsx
import {HSync} from "../../mvs/HeliosSync";
// MVS로 PlayerId 발급 요청
HSync.PlayerId()
`
- GroupList()
`tsx
import {HSync} from "../../mvs/HeliosSync";
// MVS로 GroupList 패킷 보내기
HSync.GroupList()
`
- RPC(id:ObjectIdParams, method:number, args:any[])
`tsx
// MVS로 Custom 패킷 보내기
import {HSync} from "../../mvs/HeliosSync";
// RPC 타입 선언
export enum METHOD {
ATTACK,
PUSH,
ANIMATE,
//...
}
// RPC 전송
HSync.RPC(obj.id, METHOD.ATTACK, [1, "string", object])
// 핸들러 정의
HSync.Handler().onRpcCustomHandler = (objectId, method, args, sender) => {
switch (method) {
case METHOD.ATTACK: {
console.log(objectId, method, args, sender)
}
case METHOD.PUSH: {
console.log(objectId, method, args, sender)
}
case METHOD.ANIMATE: {
console.log(objectId, method, args, sender)
}
}
}
`
Event
- InitialObject()
`tsx
import {HSync} from "../../mvs/HeliosSync";
// MVS로 InitialObject 패킷 보내기
HSync.InitialObject()
`
- CreateObject()
`tsx
import {HSync} from "../../mvs/HeliosSync";
import {MvsStore} from "@mv/mvs-sync/dist/store/ObjectStateStore";
// 오브젝트 키 정의
export enum HeliosKey{
POSITION,
ROTATION,
SCALE,
HEALTH,
ISALIVE,
DESCRIPTION,
}
// 오브젝트 생성
MvsStore.addMyObjects([
{
prefabId: PREFAB_ID,
value: [
HSync.object.getVectorHvInstance(HeliosKey.POSITION, X, Y, Z),
HSync.object.getVectorHvInstance(HeliosKey.ROTATION, X, Y, Z),
HSync.object.getVectorHvInstance(HeliosKey.SCALE, X, Y, Z),
HSync.object.getNumberHvInstance(HeliosKey.HEALTH, HP),
HSync.object.getBooleanHvInstance(HeliosKey.ISALIVE, true),
HSync.object.getStringHvInstance(HeliosKey.DESCRIPTION, "Hello World"),
]
}
]) // MvsStore에서 생성 패킷을 전송
`
- UpdateObject()
`tsx
import {HSync} from "../../mvs/HeliosSync";
import {MvsStore} from "@mv/mvs-sync/dist/store/ObjectStateStore";
// 오브젝트 갱신. 변경사항을 저장하고 33ms마다 동기화
MvsStore.postUpdateObject([
{
clientInstanceId: clientInstanceId,
value: HSync.object.getVectorHvInstance(HeliosKey.POSITION, X, Y, Z)
}
]) // MvsStore에서 갱신 패킷을 전송
`
- RemoveObject()
`tsx
import {MvsStore} from "@mv/mvs-sync/dist/store/ObjectStateStore";
// 오브젝트 삭제
MvsStore.removeMyObjects([
{
prefabId: PREFAB_ID,
clientInstanceId: CLIENT_INSTANCE_ID,
instanceId: INSTANCE_ID
}
]) // MvsStore에서 삭제 패킷을 전송
`
MVS 프로토콜
`tsx
export enum MessageId {
PKT_C_OPERATION = 1000, // 룸 점속 관련 패킷
PKT_S_OPERATION = 1001,
PKT_S_EVENT = 1002, // 동기화 패킷
}
enum OperationCode
{
HEART_BEAT = 0;
ROOM_JOIN_OR_CREATE = 1;
ROOM_LEAVE = 2;
ROOM_LIST = 3;
PLAYER_ID = 4;
GROUP_LIST = 5;
GROUP_JOIN = 6;
GROUP_LEAVE = 7;
RAISE_EVENT = 8;
INIT_VARIABLES = 9;
}
enum EventCode
{
OTHER_CLIENT_JOINED = 0;
INITIAL_OBJECTS = 1;
ADD_NETWORK_OBJECTS = 2;
REMOVE_NETWORK_OBJECTS = 3;
UPDATE_NETWORK_OBJECTS = 4;
CHANGE_OBJECTS_OWNER = 5;
RPC = 6;
}
`
- 요청과 응답 패킷의 MessageId에 해당하는 result number 확인
- syncManager.messageId로 참조
$3
`tsx
export enum ResultCode {
SUCCESS = 0,
FAILED = 1,
// Room 관련 성공
SUCCESS_ROOM_CREATE = 2,
SUCCESS_ROOM_JOINED = 3,
// Group 관련 성공
SUCCESS_GROUP_CREATE = 4,
SUCCESS_GROUP_JOINED = 5,
// Room 관련 에러
FAILED_ROOM_NOT_EXISTS_ROOM = 10,
FAILED_ROOM_ALREADY_EXISTS_ROOM = 11,
FAILED_ROOM_NOT_IN_ROOM = 12, // Player 가 Room 에 들어와 있지 않음
// Group 관련 에러
FAILED_GROUP_NOT_EXISTS_GROUP = 20, // 찾는 그룹이 존재하지 않음
FAILED_GROUP_NOT_IN_GROUP = 21, // 현재 Player 가 그룹 내에 있지 않음
FAILED_GROUP_ALREADY_EXISTS_GROUP = 22, // 추가하려는 그룹이 이미 존재
FAILED_GROUP_SAME_GROUP = 23,
FAILED_GROUP_NOT_EXISTS_PLAYER = 24, // 찾는 플레이어가 존재하지 않음
FAILED_GROUP_ALREADY_EXISTS_PLAYER = 25, // 추가하려는 플레이어가 이미 존재
}
``