Young-Hoon의 모든 글

Ottinger’s Rules for Variable and Class Naming

Ottinger’s Rules for Variable and Class Naming

Ottinger’s Rules for Variable and Class Naming

Tim Ottinger

Brad Appleton took the time to convert the original textual version to hypertext, and I thank him for the this encouragement.

This is an archived copy; the original (and maintained) version lives here.

This paper grew out of some postings made on usenet, specifically comp.object, in 1997. There was some response, and so it is presented here in entirety, enhanced a bit.



  1. Use Pronounceable names
  2. Avoid Encodings
  3. Don’t be too cute
  4. Most meanings have multiple words. Pick ONE
  5. Most words have multiple meanings
  6. Nouns and Verb Phrases
  7. Use Solution Domain Names
  8. Also Use Problem Domain Names
  9. Avoid Mental Mapping
  10. Nothing is intuitive
  11. Avoid Disinformation
  12. Names are only Meaningful in Context
  13. Don’t add Artificial Context
  14. No Disambiguation without Differentiation

Introduction

When a new developer joins a project which is already in progress, there is a steep learning curve. If the new developer already knows the methodology and programming language, some of this is reduced. If the new developer already knows the problem domain fairly well, this also shortens the ramp-up time.

There is often a great deal of artificial curve which is added to a project by decree or by accident. This has the opposite effect; it increases ramp-up time and can hurt the new developer’s time-to-first-contribution considerably. And not only the first contribution, but the next several.

The goal of these rules set is to help avoid creating one type of artificial learning curve, that of deciphering or memorizing strange names.

The rules were developed in group discussions, largely by examining poor names and dissecting them to determine the cause of their "badness".

    Use Pronounceable names

    If you can’t pronounce it, you can’t discuss it without sounding like an idiot. "Well, over here on the bee cee arr three cee enn tee we have a pee ess zee kyew int, see?"

    I company I know has genymdhms (generation date, year, month day, hour, minute and second) so they walked around saying "gen why emm dee aich emm ess". I have an annoying habit of pronouncing everything as-written, so I started saying "gen-yah-mudda-hims". It later was being called this by a host of designers and analysts, and we still sounded silly. But we were in on the joke, so it was fun. Fun or not, don’t do that.
      
    It would have been so much better if it had been called generation_timestamp. "Hey, Mikey, take a look at this record! The generation timestamp is tomorrow! How can that be?"

    Avoid Encodings

    Encoded names require deciphering. This is true for Hungarian and other `type-encoded’ or otherwise encoded variable names. To allow any encoded prefixes or suffixes in code is suspect, but to require it seems irresponsible inasmuch as it requires each new employee to learn an encoding "language" in addition to learning the (usually considerable) body of code that they’ll be working in.

    When you worked in name-length-challenged programs, you probably violated this rule with impunity and regret. Fortran forced it by basing type on the first letter, making the first letter a `code’ for the type. Hungarian has taken this to a whole new level.

    We’ve all seen bizarre encoded naming standards for files, producing (real name) cccoproi.sc and SRD2T3. This is an artificially-created naming standard in the modern world of long filenames, though it had it’s time.
    This isn’t intended as an attack on Hungarian notation out of malice toward Microsoft or Windows. It’s a simple rule of simplifying and clarifying names. HN was pretty important back when everything was an integer handle or a long pointer, but in C++ we have (and should have) a much richer type system. We don’t need HN any more.  Besides, encoded names are seldom pronounceable ([#1]).

    Of course, you can get used to anything, but why create an artificial learning curve for new hires? Avoid this if you can avoid it.

    Don’t be too cute

    If the names are too clever, they will be memorable only to people who share your sense of humor and remember the joke. Will the people coming after you really remember what HolyHandGrenade is supposed to do in your program? Sure, it’s cute, but maybe in this case ListItemRemover might be a better name. I’ve seen Monty Python’s The Holy Grail, but it may take me a while to realize what you are meaning to do.

    I’ve seen other similar cutesy namings fail.

    Given the choice, choose clarity over entertainment value. It’s a good practice.

    Most meanings have multiple words. Pick ONE

    Pick one word for one abstract function and stick with it.  I hear that the Eiffel libraries excel at this, and I know that the C++ STL is very consistent. Sometimes the names seem a little odd (like pop_front for a list), but being consistent will reduce the overall learning curve for the whole library.

    For instance, it’s confusing to have fetch, retrieve and get as same-acting methods of the different classes. How do you remember which method name goes with which class? Sadly, you often have to remember who wrote the library in order to remember which term was used. Otherwise, you spend an awful lot of time browsing through headers and previous code samples. This is a considerably worse practice than the use of encodings.

    Likewise, it’s confusing to have a controller and a manager and a driver in the same process. What is the essential difference between a DeviceManager and a ProtocolController? Why are both not controllers, or both not managers? The name leads you to expect two objects that have very different type as well as having different classes.

    We can take advantage of this to create consistent interfaces and simplify learning dramatically.

    Most words have multiple meanings

    Don’t use the same word for two purposes, if you can at all avoid it.

    This is the inverse of the previous rule. When you use different terms, it leads one to think that there are different types underlying them. If I use DeviceManager and ProtocolManager, it leads one to expect the two to have very similar interfaces. If I can call DeviceManager::add(), I should be able to call ProtocolManager::add(). Why? Because the name created an association between the two. I expect to see *Manager::add() now.

    If you use the same word, but you have very different interfaces, this isn’t a total evil (see  #12 ), but it does cause some confusion. If you system or your module is small enough, or your controls rigorous enough to prevent synonyms, then that’s great.

    If you’re learning a framework, though, you need to be most careful not to be fooled by synonyms. While you should be able to count on the names denoting type, you frequently cannot.

    Remember also that it’s not polite at all to have the same name in two scopes.

    Nouns and Verb Phrases

    Classes and objects should have noun or noun phrase names.

    There are some methods (commonly called "accessors") which calculate and/or return a value. These can and probably should have noun names. This way accessing a person’s first name can read like:

            string x = person.name();

    Other methods (sometimes called "manipulators", but not so commonly anymore) cause something to happen. These should have verb or verb-phrase names. This way, changing a name would read like:

            fred.changeNameTo("mike")

    As a class designer, does this sound boringly unimportant? If so, then go write code that uses your classes. The best way to test an interface is to use it and look for ugly, contrived, or confusing text. This really helps.

    Use Solution Domain Names

    Go ahead, use computer science (CS) terms, algorithm names, pattern names, math terms, etc.

    Yeah, it’s a bit heretical, but you don’t want your developers having to run back and forth to the customer asking what every name means if they already know the concept by a different name.

    We’re talking about code here, so you’re more likely to have your code maintained by a CS major or informed programmer than by a domain expert with no programming background. End users of a system very seldom read the code, but the maintainers have to.

    Also Use Problem Domain Names

    When there is no `programmer-ese’ for what you’re doing, use the name from the problem domain. At least the programmer who maintains your code can ask his boss what it means.

    In analysis, of course, this is the superior rule to  [Use Solution Domain Names], because the end-user is the target audience.

    Avoid Mental Mapping

    Readers shouldn’t have to mentally translate your names into other names they already know.

    There are some unfortunate examples for this. One of them is Microsoft’s choice to call the things that walk through a list Enumerators instead of Iterators.  This is sad because the term iterator is in common use in software circles and was completely appropriate to the domain (see  Pick One ) and also because the term enumeration typically has a very different meaning (see  Multiple Meanings ). Between the two, most developers have to translate enumerator to iterator mentally as the conversations about such things go on.

    This problem generally  arises from a choice to use neither  problem domain terms nor  solution domain terms.

    Nothing is intuitive

    Sadly, and in contradiction to the above, all names require some mental mapping, since this is the nature of language. If you use a term which might not be known to your audience, you must map it to the concept you’d like it to represent.

    For this reason, most important names should be in a glossary or should be explained in comments at least. Even if they’re parameters or local variables. Even if they’re inside the static member of a class, unless the term is completely in harmony with all of these naming rules.

    Avoid Disinformation

    Avoid words which already mean something else. For example, "hp", "aix", and "sco" would be horrible variable names because they are the names of Unix platforms or variants. Even if you are coding a hypotenuse and "hp" looks like a good abbreviation, it violates too many rules and also is disinformative.

    Likewise don’t refer to a grouping of accounts as an AccountList unless it’s actually a list. A list means something to CS people. It denotes a certain type of data structure. If the container isn’t a list, you’ve disinformed the programmer who has to maintain your code. AccountGroup or BunchOfAccounts would have been better.

    The absolute worse example of this would be the use of lower-case L or uppercase o as variable names, especially in combination. The problem, of course is in code where such things as this occur:

        int a = l;
        if ( O = l )
            a = O1;
        else
            l = 0;

    You think that I made this one up, right? Sorry. I’ve examined code this year (1997) where such things were abundant. It’s a great technique for shrouding your code.

    When I complained, one author told me that I should use a different font so that the differences were more obvious. I think that the problem could be more easily and finally corrected by search-and-replace than by publishing a requirement that all future readers to choose Font X..

    Names are only Meaningful in Context

    There are few names which are meaningful in and of themselves. Most, however are not. Instead, you need to place names in context for your reader by enclosing them in classes, well-named functions, or comments.

    The term `tree‘ needs some disambiguation, for example if the application is a forestry application. You may have syntax trees, red-black or b-trees, and also elms, oaks, and pines. The word `tree’ is a good word, and is not to be avoided, but it must be placed in context every place it is used.

    If you review a program or enter into a conversation where the word "tree" could mean either, and you aren’t sure, then the author (speaker) will have to clarify.

    Don’t add Artificial Context

    In an imaginary application called "Gas Station Deluxe", it is a bad idea to prefix every class with `GSD‘ if there is a chance that the class might later be used in "Inventory Manager" (at which time the prefix becomes meaningless).

    Likewise, say you invented a `Mailing Address’ class in GSD‘s accounting module, and you named it AccountAddress. Later, you need a mailing address for your customers. Do you use `AccountAddress‘?

    In both these cases, the naming reveals an earlier short-sightedness regarding reuse. It shows that there was a failing at the design level to look for common classes across an application.

    Sadly, this is the standard being used by many Java authors. Even in C++, this is becoming increasingly common. We need language support for this type of work. I’ve not had too much trouble with it in Python, but I’m watching out. You should also.

    The names `accountAddress‘ and `customerAddress‘ are fine names for instances of the class.

    No Disambiguation without Differentiation

    This is a problem that usually arises from writing code solely for the compiler/interpreter. You can’t have the same name referring to two things in the same scope, so you change one of them. Well, that’s better than misspelling one (I’ve seen code that looks like this was intentional, and correcting the spelling prevented compiles due to symbol clashes), but there should be some fundamental change in name that make it clear that they are different.

    Imagine that you have a Product class. If you have another called ProductInfo or ProductData, you have failed to make the names different. Info and Data are like "stuff": basically meaningless. Likewise, using the words Class or Object in an OO system is so much noise; can you imagine having CustomerObject and Customer as two different class names?

    MoneyAmount is no better than `money‘. CustomerInfo is no better than Customer. The word `variable‘ should never appear in a variable name. The word `table‘ should never appear in a table name. How is NameString better than Name? Would a Name ever be a floating point number? Probably not. If so, it breaks an earlier rule about disinformation.

    There is an application I know of where this is illustrated. I’ve changed the name of the thing we’re getting to protect the guilty, but the exact form of the error is:

             getSomething();
             getSomethings();
             getSomethingInfo();

    The second tells you there are many of these things. The first lets you know you’ll get one, but which? The third tells you nothing more than the first, but the compiler (and hopefully the author) can tell them apart. You are going to have to work harder.

    Try to disambiguate in such a way that the reader knows what the different versions offer her, instead of merely that they’re different.

Final Words …

The hardest thing about choosing good names is that it requires good descriptive skills and a shared cultural background. This is a teaching issue, rather than a technical, business, or management issue. As a result many people in this field don’t do it very well.

Follow some of these rules, and see if you don’t improve the readability of your code. If you are maintaining someone else’s code, make changes to resolve these problems. It will pay off in the long run.

블록딜 이란?

https://news.naver.com/main/ranking/read.nhn?mode=LSD&mid=shm&sid1=001&oid=015&aid=0004520361&rankingType=RANKING

https://nurias5.tistory.com/44


블록 딜(Block deal)

주식을 대량으로 보유한 기관 또는 개인이, 사전에 이 주식을 인수할 매수자를 구해, 장외 시간에 주식을 매도하는 거래를 의미 한다.

블록딜을 하는 이유?

대량 주식 매각을 효율적으로 하기 위해서 라고 한다. 장중 대량 매각 시장중 가격변화가 과도하게 나타날 수 있고, 그렇다면 원하는 시점과 가격에 팔 수 없기 때문. 결국 장외 시간 거래를 통해 시장에 영향을 미치지 않도록 하기 위함.

미치는 영향

지분을 상당부분 가지고 있는 주주가 주식을 대량으로 매각하는 것은 악재이다. 즉, 주가가 떨어질 가능성이 높아진다. 지분을 상당수준 가지고 있는 주주는 그 회사 내부 사정에 대해 더 잘 알고 있을 확률이 높기 때문에, 설사 다른 이유로 주식을 매각한다고 하더라도 시장에서는 부정적인 신호로 받아들이는게 일반적이다. 또한 5~10% 할인된 가격으로 거래가 체결되기 때문에 단기적으로나마 주가가 떨어질 가능성이 더 크다.


살아 남다.

요즘 2~40대 대부분 재테크 열풍인것같다. 온라인 서점 베스트 셀러 목록에보면 재테크에 관한 서적이 일년 내내 있고 직장 동료들의 화젯거리도 대부분 돈을 어떻게 빨리 그리고 남들보다 많이 벌수 있는가? 에 대한 것들이 대부분 인것 같다. 내가 보기에 그들은 현재 자신이 가진 자산이 자신이 원하는 것을 하기에 부족하다고 생각하는 것 같다.

나는 2018년 부터 일해오면서 내가 벌었던 돈을 그해에 거의 대부분 소비했던 것 같다. 2017년까지 혼자서 게임을 만든다고 죽쑤다가 모아둔 돈을 전부 날리고 다시 취업 하게 되었을 때 가졌던 마음가짐이 있었다. 그것은 바로 “나의 소득 한도 내에서 하고 싶은 모든 것을 하자 시간이 흘러 후회가 없도록” 이었다. 돈 생각 하지 않고 그때그때 내가 원했던 것들 (물건을 사는 것이던 내가 무슨 행동을 하는 것이던)은 살짝 고민을 했었던 적도 있기는 했지만 결국엔 내가 바라는대로 행동 했고 아직까지는 내가 했던 선택이 그렇게 나에게 악영향을 끼친것은 없었던 것 같다. 오히려 그 선택으로 인해 내가 성취감을 느끼거나 운좋은 어떤 일이 생긴다거나 하는 경우가 많았던것 같다.



Package error, Unsupported 16-bit application

https://answers.unrealengine.com/questions/327266/unsupported-16-bit-application.html

빌드 테스트 중 링크안에 있는 에러가 발생했다. 이유는 모르겠지만 프로젝트 폴더의 immediate 폴더와 saved 폴더를 제거하고 generated visual studio project 를 한뒤 재컴파일 하니 정상으로 돌아왔다. 특별히 한것도 없는데 이상한데 이문제는 나중에 자세히 알아봐야겠다.

UnrealEngine4 Network Description

언리얼 네트워크 정리

Network Conpendium의 요약정리

자료를 참고하여 정리하는 과정에서 작성자의 오해나 이해가 부족한 점이 있을 수 있음을 알려드립니다

Network Multiplayers 게임관련 주요 클래스

GameInstance

GameMode

GameState

Pawn (and Character, which inherits from Pawn)

PlayerController

PlayerState

게임 데이터를 저장할 때 고려해야 할 사항

 – Pawn은 게임 내에서 죽거나 제거되는 경우가 많으며 그때마다 폰 클래스에 저장한 데이터도 사라진다

 – PlayerController, PlayerState는 새 레벨이 로드되지 않는 한 폰이 제거되어도 계속 존재한다

GameInstance

 – 게임인스턴스는 게임엔진이 시작될 때부터 종료할 때까지 존재한다

 – 서버와 클라이언트에 각각 하나의 게임인스턴스가 있고 서로 통신하지는 않는다

 – 현재 게임세션의 밖에 존재하며 레벨로드에 영향을 받지 않은 상태로 게임을 구성한다

 – 영구적인 정보를 저장할 수 있는 적합한 장소이다

서버에만 존재하는 객체

 – GameMode

서버와 모든 클라이언트에 존재하는 객체

 – GameState, PlayerState, Pawn

서버와 소유한 클라이언트에 존재하는 객체

 – PlayerController 는 클라이언트와 서버에 존재하지만 다른 클라이언트끼리는 공유하지 않는다

 – PlayerController는 클라이언트 서버간의 통신에 관련한 작업을 주로 한다

클라이언트에만 존재하는 객체

 – HUD, UMG Widgets

GameMode 클래스의 오버라드 가능한 함수

 – 게임의 룰을 결정한다(플레이어 수, 최고점수 등)

 – Ready to start Match : 클라이언트 수가 채워지면 true를 리턴하고 아니면 false리턴

 – Event On Post Login : 클라이언트의 PlayerController를 파라미터를 통해 가져온다. PlayerController를 배열에 저장해 놓으면 나중에 유용하다

 – Choose Player Start : 다수개의 Player Start 액터가 레벨상에 존하는 경우에 그 중 아직 점유되지 않은 Player Start를 찾아 리턴한다

 – Start Match, Restart Game, End Match, Has Match Started, Abord Match, Has Match Ended, Is Match in Progress, Event OnSetMatchState, Get Match State 등의 함수 및 이벤트를 오버라이드할 수 있고 수동으로 호출도 가능하다

 – 이 함수들은 Ready to start Match 함수가 true 를 리턴한 후에 대부분 자동으로 호출되지만 수동으로 호출도 가능하다

GameState

 – 클라이언트/서버간의 게임의 현재 상태에 대한 정보교환을 위한 중요한 클래스

 – 멀티 플레이어어 게임에서 중요한 정보인 접속된 플레이어 리스트(PlayerState의 리스트)를 포함한다

 – GameState는 모든 클라이언트에게 Replicated 되므로 모든 클라이언트가 이 객체에 접근할 수 있다

 – 멀티플레이어 게임에서 가장 핵심적인 클래스 중에 하나이다

 – GameMode가 승리를 위한 점수를 가지고 있는 반면, GameState는 현재까지 취득한 점수를 가지고 있다

 – GameState에는 개발자가 임의의 정보(배열이나 구조체 등)를 저장할 수 있다

 – GameMode에 비해 개발자가 다루어야 할 작업은 적은 편이지만 이벤트 그래프에는 모든 클라이언트가 알아야 할 로직을 작성할 수 있다

 – PlayerArray MatchState, ElapsedTime은 replicated 설정되어 있으므로 모든 클라이언트에서 접근할 수 있다

 – GameState에 선언한 변수를 Replicated 설정하고 Switch has Authority 를 사용하여 서버측에서 값을 변경하면 모든 클라이언트에서 확인할 수 있다

PlayerState

 – 모든 접속된 클라이언트는 현재 클라이언트의 정보를 포함하고 있는 한개의 PlayerState 객체를 갖는다

 – PlayerState 객체는 모든 클라이언트에게 Replicated 되므로 어떤 클라이언트에서 다른 클라이언트의 정보를 접할 수가 있다

 – 현재 클라이언트에서 다른 클라이언트의 PlayerState 객체에 접근하는 쉬운 방법은 GameState::getPlayerArray 를 이용하는 것이다

 – PlayerName, Score 등 다른 클라이언트에게 제공해야 하는 다양한 정보(커스텀 변수)를 이 객체에 저장하여 다른 클라이언트에게 전달할 수 있다

 – PlayerPawn이 Destroy 되더라도 PlayerState는 유지된다

Pawn

 – Actor를 기반으로 파생된 클래스이며 플레이어에 의해 조종될 수 있는 액터이다

 – 플레이어는 한번에 한개의 폰을 소유할 수 있으며 쉽게 다른 폰으로 전환할 수 있다(un-possessing, re-possessing)

 – Pawn은 대부분 모든 클라이언트에게 Replicated 된다. Actor Replicated 설정된 상태

 – 폰은 대부분의 경우 사람 형태이지만 동물이나 자동차, 비행기, 배, 블럭 등도 될 수 있다

 – Pawn의 하위 클래스인 Character클래스는 네트워크에서 지원되는 MovementComponent를 포함하고 있어서 위치, 회전 등의 정보가 Replicate 된다

Actor Replication

– 맵에 배치된 액터를 선택하고 [디테일] 뷰 / Replication / 안에 있는 체크박스이다 

– Net Load on Client : 클라이언트에 맵이 로드되면서 동시에 이 항목이 체크된 해당 액터도 맵과 함께 클라이언트에게 보여지게 된다

 – 서버 측에는 위의 항목과 무관하게 보여진다

 – Replicate : 서버에 스폰될 때 클라이언트에게도 Replicate 된다. 

 – 서버측에 스폰하는 것이 아니라 클라이언트에 스폰될 때는 위의 항목설정과 무관하게 액터가 보여진다

 – 클라이언트에서 스폰하는 경우에는 서버측에 Replicate 되지는 않는다

 – 게임의 승패에 영향을 주는 중요한 액터를 생성할 때는 반드시 서버에 스폰하고 클라이언트에게 Replicate하는 것이 보안상 최선책이다

 – 게임의 승패에 영향이 없는 장식성 액터의 출력도 서버에 스폰하여 클라이언트에 Replicate해도 된다

 – 서버에서 Replicate설정된 액터를 삭제하면 모든 Replicate 한 클라이언트에서도 해당 액터가 삭제된다

 – 네트워크 상에서는 클라이언트가 Character를 움직이는 것이 아니라 클라이언트의 입력을 받아서 서버에서 Character를 움직이고 클라이언트에 Replicate 된다

Event replication

https://docs.unrealengine.com/latest/INT/Gameplay/Networking/Blueprints/index.html

 – 서버측에서 발생하는 이벤트만 유효하게 사용될 수 있도록 이벤트 함수 안에서 Switch Has Authority 노드를 사용하여 현재 인스턴스가 서버측에서 실행되는 것인지 확인 할 수 있다

Switch has Authority

 – 현재의 스크립트가 서버측에서 실행되는 클라이언트 로직인지 리모트 클라이언트에서 실행되는 로직인지 확인하여 로직을 분기한다

 – 현재 스크립트를 실행하는 머신이 서버인지 클라인지를 식별하여 실행내용을 다르게 작성할 수 있다

 – 실행 중인 이벤트 함수가 서버측에서 실행 중인지 확인하여 그 결과를 다른 클라이언트에게 복제할 때도 사용할 수 있다

 – 네트워크 게임은 모든 클라이언트의 화면의 내용이 같고 보는 방향만 다르므로 맵은 모두 동일하다고 할 수 있다

 – 현재 실행되고 있는 머신이 서버인지 클라이언트인지를 구분하는 이유는 게임의 승패와 관련한 중요한 변수의 변경은 서버측 머신에서만 하려고 하기 때문이다

Function Replication (Remote Procedure Calls or RPCs for short)

https://docs.unrealengine.com/latest/INT/Gameplay/HowTo/Networking/ReplicateFunction/Blueprints/index.html

https://docs.unrealengine.com/latest/INT/Gameplay/Networking/Blueprints/index.html

 – 로컬 머신에서 호출되어 다른 머신에서 실행된다

 – 클라이언트, 서버간의 데이터 전송방법으로 유용하게 사용된다

 – Reliable : 네트워크 상황과 무관하게 데이터가 반드시 전달된다

 – Unreliable : 네트워크 상황에 따라 전달하려는 데이터가 손실될 수도 있다

 – Multicast : 서버측에서 호출되어 서버에서 실행되고 모든 클라이언트들에게도 포워드된다

 – Run on Server : 클라이언트 측에서 호출하고 서버에서만 실행된다

 – Run on owning Client : 서버측에서 호출하고 소유한(owning client)클라이언트에서만 실행된다

 – PlayerController 에 의해 소유된 폰은 위의 2가지 타입(Run on Server, Run on owning Client)의 함수를 가질 수 있다

 – Run on Server, Run on owning Client 함수의 호출과 선언은 클라이언트의 PlayerController, PlayerState, PlayerController가 소유한 Pawn에서만 해야한다

Multicast Function 테스트

 – Multicast 로 설정된 함수를 서버 윈도우에서 실행하면 서버 화면 뿐만 아니라 다른 모든 클라이언트 화면에서도 그대로 재현된다. 그러나 클라이언트 화면에서 Multicast 함수를 실행하면 현재 클라이언트에서만 효과가 나타난다

 – Multicast 로 설정된 함수는 서버에서 호출되고 서버에서 실행되어 모든 클라이언트에게 포워드되어 실행되기 때문이다

Server Function 테스트

 – 클라이언트가 서버로 데이터를 전송하기 위한 주요 방법이다

 – Ron on Server 로 설정된 함수를 클라이언트에서 호출하면 서버측 화면에서만 효과가 나타나고 현재 클라이언트 화면에는 효과가 나타나지 않는다

 – Run on Server로 설정된 함수는 클라이언트에서 호출되어 서버에서 실행되기 때문이다

 – Run on Server로 설정된 함수를 호출하여 서버에서 특정액터의 변수의 값을 변경하고 그 액터가 Replicates 로 설정된 경우에는 클라이언트가 호출한 로직이 서버에서 실행되고 다른 클라이언트에게 Replicated된다

 – 클라이언트 측에서 호출할 수 있으므로 Run on Server로 설정된 함수 안에서 다시 Multicast 함수를 호출하면 클라이언트가 호출한 로직은 서버에서 실행되고 모든 클라이언트에게 포워드되어 실행되므로 모든 클라이언트에서 효과가 나타난다

Run On Owning Client Function 테스트

 – 서버에서 호출할 수 있고 특정 클라이언트만 선택하여 해당 클라이언트에서만 실행되도록 할 때 사용한다

 – 예를 들어 서버측 스크립트 실행 중 특정 클라이언트의 폰이 트리거에 들어가는 경우 해당 폰을 소유한 클라이언트에게만 이벤트 실행결과를 보여주려는 경우에 사용할 수 있다

Replicating Variables

https://docs.unrealengine.com/latest/INT/Gameplay/HowTo/Networking/ReplicateVariable/index.html

액터 클래스에 선언된 변수가 Replicated 로 설정된 경우, 서버에서 해당 변수의 값을 변경하면 모든 클라이언트 머신에도 변경된 값이 복제된다. 이 때 반드시 서버측에서 값이 변경된 경우에만 클라이언트에 복제가 된다

Actor Replication, Event Replication

https://docs.unrealengine.com/latest/INT/Gameplay/HowTo/Networking/ReplicateActor/Blueprints/index.html

https://docs.unrealengine.com/latest/INT/Gameplay/Networking/Blueprints/index.html

https://docs.unrealengine.com/latest/INT/Gameplay/Networking/Actors/index.html

Testing Multiplayers

https://docs.unrealengine.com/latest/INT/Gameplay/HowTo/Networking/TestMultiplayer/index.html

변수복제 VS 함수복제

변수복제와 함수복제를 위해서는 서버측에서 조작되는 객체가 클라이언트 측에도 있어야 한다. 그러한 이유로 변수복제와 함수복제에 사용할 수 있는 객체는 PlayerController 이거나 Pawn 일 경우가 많다

모든 클라이언트에 존재하는 PlayerController 객체는 서버측에도 생성된다. 그러므로 서버측에서 특정 PlayerController의 변수를 변경하고 그 변수의 값이 클라이언트 측에도 변경되도록 하려면 해당 변수를 Replication 설정해야 한다. 이렇게 하면 특정 PlayerController 의 속성을 변경하면 자동으로 해당 PlayerController 가 존재하는 클라이언트 측에서도 그 변수의 값이 변경된다. 

서버측에서는 모든 클라이언트의 PlayerController를 가지므로 변수복제를 이용하여 모든 클라이언트의 화면에 다른 값을 표시할 수가 있다.

변수복제는 서버측에서 변경된 변수의 값이 클라이언트에서도 변경되도록 할 때 사용한다. 그 반대는 안된다

서버측에서 모든 클라이언트의 PlayerController를 구할 때는 Get All Actors of Class() 함수노드를 사용하면 된다

레벨에 올려진 캐릭터는 모든 클라이언트에서 서로를 볼 수가 있기 때문에 모든 클라이언트의 컴퓨터에는 모든 캐릭터가 기능을 하고 있다고 할 수 있다. 그런데 게임 중에서 특정 캐릭터가 점프를 한다면 모든 클라이언트 화면에서 해당 캐릭터가 점프하는 동작이 보여져야 한다. 이 때는 서버측에서 점프 동작을 수행하고 그 동작이 모든 클라이언트에 존재하는 해당 캐릭터에 그대로 재현되어야 한다. 이러한 일은 함수복제 중에서도 Multicast 설정으로 할 수 있다

서버측에서 특정 클라이언트의 캐릭터에 접근할 때는 PlayerController:: Get Controlled Pawn() 함수노드를 사용하면 된다