mvs-sync-cro
v1.0.18
Published
Modules for synchronizing with mvs synchronization server
Downloads
12
Readme
- MVS API 문서
개요
9/6 수정, v 1.0.18
- HeliosNetwork : 인스턴스 생성 시 NameServer, MV Master로의 연결 관리. 대부분의 유저 프로시저 구현
- LoadBalancingService : NameServer, MV Master 와의 통신
- MvsStore : 동기화 정보 관리
- SyncManager : 동기화 관리
- MVS와의 연결 소켓 관리 →
#initialize
- 클라이언트의 요청에 따른 메시지 작성 및 전송 →
sendPacket
- 응답 패킷의 메시지 ID에 따른 로직 구현 →
#ReadProtocol
- 메시지 ID에 따른 콜백함수 자동 호출 →
onReceivePacket
- MVS와의 연결 소켓 관리 →
ChangeLog
- v 1.0.18
- add/update/remove NetworkObjectCustomHandler가 적용 이후에 실행되도록 타이밍 조정
- getBooleanHvInstance() 메소드 추가
- CreateOrJoinRoom()에 falsy value 체크 추가
- v 1.0.17
- 환경변수를 사용하지 않고 HeliosConfig를 사용해 HeliosNetwork 객체 생성
- WebRequest 요청에 대한 에러 핸들링 추가
- CreateOrJoinRoom() 메소드 추가
- InjectOnRoomJoinOrCreateHandler 핸들러 추가
- 패킷 사이즈 변경(4->8)
- v 1.0.16
- 새로운 프로토콜 핸들러 추가(그룹 오너 변경, 룸/그룹 입장, 룸 퇴장)
- 룸 입장 및 생성 구분, MVS와의 사용자 인증 연동
- 그룹 오너 추가
- v 1.0.15
- 프로토콜 변경
- 웹소켓 연결 후 heartbeat 전송
- v 1.0.14
- 오브젝트 후처리 로직 fix
- v 1.0.13
- 동기화 루프 설정(33ms)
- RPC 패킷 추가
- Name Server, MV Master(C#) 연동
- 프로토콜 변경 적용
- v 1.0.12
- 오브젝트 변경 감지 자동화
- v 1.0.11
- 패킷을 operation, event로 구분
- SyncManager의 동작을 래핑한 HeliosNetwork API 제공
- v 1.0.10
- WebTransport 적용
- compile shell 변경(환경변수 자동 설정)
- Console Message 세분화 : info, invalidMessage, invalidProtocol 추가
- 핸들러 미구현시의 에러를 로그로 변경
- v 1.0.9
- proto-ts 적용
- 공통 SapClient 구현, 해당 모듈을 사용해 LBService 호출
- syncType, propsId 적용
- v 1.0.8
- UX 대응을 위해 Transform 커스텀 패킷으로 변경
- v 1.0.7
- Transform 삭제 및 singleton SyncManager 구현 변경
- v 1.0.6-hotfix1
- SyncManager 및 WebSocket 유일성 보장
- getInstance 오버로딩
mvsUrl: string
해당 mvs와 바로 연결mvsOrigin: string, masterUrl?: string, roomId?: number
MVM에서 받은 location과 mvsOrigin을 조합해 연결
룸 변경 후 url이 변경되면 재연결- sendPacket 시 WebSocket의 상태를 확인해 OPEN일 때까지 대기
- demo
- 룸 생성 및 이동 버튼 추가
- 와플 의존성 제거
라이브러리 개발
- 빌드 : npm run build
- 테스트 및 커버리지 확인 : npm run test (5/21일 기준 77.36%)
- 배포 : npm run build -> npm login -> npm publish --registry=http://192.168.153.214:4873
프로토콜 수정
> @mv/mvs-sync@1.0.17 compile
> cd lib/utils/bufferProtocol && ./compile_pb.sh build
## ## ## ## ######
### ### ## ## ## ##
#### #### ## ## ##
## ### ## ## ## ######
## ## ## ## ##
## ## ## ## ## ##
## ## ### ######
@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/](http://192.168.154.143:4873/)
npm i @mv/mvs-sync
MVS 분산환경 사용 시
import {HeliosNetwork} from "@mv/mvs-sync/dist/utils/HeliosNetwork";
export const HSync = await HeliosNetwork.getInstance({
mode: 'cloud',
appKey: '8f9dfaba-1d6b-47e4-bb0c-966e0070f652'
})
룸 변경
- HSync.CreateRoom() 또는 HSync.JoinRoom시 해당 룸 정보를 바탕으로 MV Master에서 적절한 MVS를 반환
지원 기능
- 룸 생성 및 입장, 룸 리스트, 유저 아이디 발급, 그룹 리스트, 그룹 입장
- 초기 객체 리스트, 객체 생성, 객체 파괴, 객체 동기화, 객체 소유권 이전 + RPC
- 사용 시나리오
- 앱 생성 후 NameServer에서 REGION 등록
- 앱 키를 환경변수로 등록하고 REGION을 명시 후 HeliosNetwork 객체 생성
- 룸 리스트 조회
- 원하는 룸 입장 또는 룸 생성
- 그룹 리스트 조회
- 원하는 그룹 입장 또는 그룹 생성
- 씬의 상태 가져오기
- 플레이어 아이디 요청
- 오브젝트 생성
- 생성한 오브젝트 동기화. 갱신 / 삭제 / 소유권 이전 등
클라이언트가 해야할 일
API 정상작동을 위해 해야할 일
- mvs-auth-server에서 생성한 앱 키를 환경변수로 등록(REACT_APP_MVS_APP_KEY=APP_UUID)
- MVS 분산환경 사용 시 REGION 정보를 NameServer에서 등록 후 인자로
- 패킷 전송은 HeliosNetwork 에서, 오브젝트 관리는 MvsStore 에서
SyncManager
클래스에 다 포함되어 있습니다.
패키지 다운로드
npm set registry http://192.168.154.143:4873
npm i @mv/mvs-sync
HeliosSync.ts 파일 생성
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 수정
"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
파일 생성
설정
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; };
- mvs-sync는
Operation
- getState()
import {HSync} from "../../mvs/HeliosSync";
// 현재 연결 상태 가져오기
expect(HSync.getState()).toEqual(ConnectState.ON_MVMASTER)
- Handler()
import {HSync} from "../../mvs/HeliosSync";
// 동기화중인 MVS 정보 가져오기
const syncManager = HSync.Handler()
- HeartBeat()
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)
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)
// 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)
import {HSync} from "../../mvs/HeliosSync";
// MVS로 JoinGroup 패킷 보내기
HSync.JoinGroup({
scene: SCENE_NUMBER,
channel: CHANNEL_ID
})
- MvsRoomList()
import {HSync} from "../../mvs/HeliosSync";
// MVS로 RoomList 패킷 보내기
HSync.RoomList().then((res)=>setRoomList(res));
HSync.Handler().onTestRoomListCustomHandler = (message) => {
const roomList = message.getRoominfosList()
}
async
RoomList()
import {HSync} from "../../mvs/HeliosSync";
// MV Master 또는 MVS로 RoomList 패킷 보내기
HSync.RoomList().then((res)=>setRoomList(res));
- PlayerId()
import {HSync} from "../../mvs/HeliosSync";
// MVS로 PlayerId 발급 요청
HSync.PlayerId()
- GroupList()
import {HSync} from "../../mvs/HeliosSync";
// MVS로 GroupList 패킷 보내기
HSync.GroupList()
- RPC(id:ObjectIdParams, method:number, args:any[])
// 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()
import {HSync} from "../../mvs/HeliosSync";
// MVS로 InitialObject 패킷 보내기
HSync.InitialObject()
- CreateObject()
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()
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()
import {MvsStore} from "@mv/mvs-sync/dist/store/ObjectStateStore";
// 오브젝트 삭제
MvsStore.removeMyObjects([
{
prefabId: PREFAB_ID,
clientInstanceId: CLIENT_INSTANCE_ID,
instanceId: INSTANCE_ID
}
]) // MvsStore에서 삭제 패킷을 전송
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로 참조
ResultMessage
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, // 추가하려는 플레이어가 이미 존재
}