1.0.18 • Published 8 months ago
@tmaxma/mvs-sync-cro v1.0.18
- 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() // 패킷을 받은 시간- asyncCreateRoom(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
  })- asyncJoinRoom(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()
  }- asyncRoomList()
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, // 추가하려는 플레이어가 이미 존재
}1.0.18
8 months ago