어떤 객체에 대한 접근을 제어하거나, 실제 객체의 대리 역할을 수행하는 구조 디자인 패턴이다.
대리인(Proxy)라는 뜻처럼 원본을 대신하여 동작, 접근 제어, 로깅, 캐싱 등을 수행한다.
어댑터 패턴과 다른점은 어댑터 패턴은 인터페이스에 맞는 행동을 하게 Wrapping만 해주는 패턴인데 프록시 패턴은 접근을 제어한다는 것에서 다르다.
접근 제어 / 권한 관리
DB같은 직접 접근은 위험한경우
접근하기 전에 권한을 검사해 통과될 경우에만 접근하게 만들 수 있다.
지연 로딩
어떤 객체(예: 대용량 이미지, 네트워크 연결, DB 쿼리)의 생성 비용이 매우 클 때, 필요한 시점까지 실제 객체를 만들지 않고, 프록시로 대체해 둘 수 있음.
예를 들어, “가상 프록시(Virtual Proxy)”를 사용하면, 클라이언트가 실제로 접근하기 전까지 원본 객체를 생성하지 않음으로써 초기 비용을 줄일 수 있다.
로깅 / 트래킹 / 모니터링
메서드 호출이 일어날 때마다 프록시가 중간에 개입하여, 로깅이나 사용 통계를 남길 수 있다.
예를 들어, 네트워크 호출 전/후에 로그를 찍거나, 요청 카운트를 세는 등 부수적인 기능을 쉽게 추가할 수 있다.
네트워크 / 원격 호출
서버에 실제로 연결하고 싶을 때, Proxy가 마치 로컬 객체인 것처럼 보여주고, 내부적으로는 원격 RPC를 수행할 수도 있다. (원격 프록시(Remote Proxy))
내부적으로는 RPC, Socket 통신 등을 통해 서버에 있는 객체를 호출하지만, 클라이언트 입장에서는 지역(Local) 객체처럼 보이게 된다.
ex) 게임에서 상점 지연 로딩
class IShop
{
public:
virtual void Enter() = 0;
};
class RealShop : public IShop
{
public:
void Enter() override
{
cout << "상점에 입장했습니다." << endl;
}
};
class ShopProxy : public IShop
{
private:
RealShop* _realShop;
int _playerLevel;
int _requiredLevel;
public:
ShopProxy(int playerLevel, int requiredLevel)
{
_playerLevel = playerLevel;
_requiredLevel = requiredLevel;
}
void Enter() override
{
if (_playerLevel < _requiredLevel)
{
cout << _requiredLevel << " 레벨 이상만 입장 가능" << endl;
return;
}
if (!_realShop)
_realShop = new RealShop();
_realShop->Enter();
}
};
int main()
{
cout << "플레이어 레벨 : 5" << endl;
IShop* shop = new ShopProxy(5, 10);
shop->Enter();
cout << endl << "[플레이어 레벨: 15]" << endl;
IShop* highLevelShop = new ShopProxy(15, 10);
highLevelShop->Enter();
}
GameState는 특정 클라를 특정할 수 없어서
NetMulticast를 써서 모든 클라가 메세지를 받게 구현해야함
Replicated가 되있다고 해도 값이 바뀌자마자 전달되는게 아님
연속되서 바뀌면 텀을 두고 발신함
값이 바뀐다고 바로 전달되는게 아님
값을 수신하는 기준은 네트워크 설정에 따라 다름
기본적으로 Replicated는 UDP임
내 클라에선 잘 되겠지만 실제 네트워크로 들어가면 패킷 손실이 일어날 수 있음
언리얼에도 네트워크를 일부로 구리게 설정해서 테스트해볼 수 있음
보통 GameState or GameMode에서 ServerTick 오차를 얻을 수 있는데 그걸로 타이머를 보정함
GameServerWorldTimeSecond?
지속적으로 서버의 시간을 받아오면서 그걸로 보정을 해야한다 라는 내용이라 함
https://vorixo.github.io/devtricks/non-destructive-synced-net-clock/
만약 사용하는 GameMode가 GameModeBase를 상속 받았다면 GameState도 GameStateBase를 반드시 써야함.
BeginPlay가 작동을 안함;
UI에서 커밋시 이벤트는 Enter, 포커스 벗어남, ESC같은 키로 벗어난거 3가지에서 다 실행된다.
특히 Enter로 해버리면 포커스 벗어남이랑 같이 실행되서 2번 실행된다 주의하자