1.0.18 • Published 4 months ago

mvs-sync-cro v1.0.18

Weekly downloads
-
License
MIT
Repository
-
Last release
4 months ago
  • 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

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

코드 위치 및 사용

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
  • 사용 시나리오
    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 파일 생성

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;
    };

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에서 삭제 패킷을 전송

MVS 프로토콜

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

4 months ago

1.0.0

2 years ago