디시인사이드 갤러리

마이너 갤러리 이슈박스, 최근방문 갤러리

갤러리 본문 영역

[정보] [lua]개발용 모드 gvv 업뎃 많이함. lua metatable설명

ㅇㅇ(121.137) 2020.09.07 22:26:24
조회 530 추천 2 댓글 7
														

https://mods.factorio.com/mod/gvv/changelog


버전을 0.2.0까지 올렸는데, 이유는 별거없고 0.1.xx 세번째 숫자만 올리니까 인게임 changelog가 과거내용이 맨 위에 나와서 나중엔 화면에 안들어오더라고...

이렇게 first release가 맨위에 나옴 이뭐병...


viewimage.php?id=2bbcd332eac031a9&no=24b0d769e1d32ca73fec86fa11d02831f774ca47ac4dd7dcba669517d2fdc459940edbcc853bfaaf6876474e3cc7777da2355d097e13f7ef42ee4765943a2599fc666f3d


그래서 0.2.0으로 올림. 이유 진짜 단순하지



첨부터있었나 나중에 만들어넣은건가 기억은 안나는데,

이렇게 진단기능이 있다.

샘플로 쓴 세이브파일은 디싱크 심심하면 일어나던 마운틴 포트리스 옛날에 저장해둔 거.

이 시나리오는 정말로 방대하고 오류도 가득해서 정말 좋은 샘플이 되었다.


viewimage.php?id=2bbcd332eac031a9&no=24b0d769e1d32ca73fec86fa11d02831f774ca47ac4dd7dcba669517d2fdc459940edbcc853bfaaf6876474e3cc7777da2355d097e13f7ef18ec4b6b9d69239bddfe73f8


table index is nil 이라는 오류가 뜨더라고.

원인을 찾다가보니

remote.call에서

https://lua-api.factorio.com/latest/LuaRemote.html

다른 모드의 테이블을 불러올 때, 테이블의 키 라고 하는 항목이 nil(값없음) 이면 오류가 나더라고.


table[key] = value 일때 key말하는거임. 여기다가 보통은 못넣는 nil을 넣을 수 있는데 그 방법이 뭔고 했더니,

일종의 metatable인 LuaEntity 같은 object를 key 값으로 쳐넣는거야.

일단 lua의 metatable이 뭔지 이야기 하고 넘어가야겠다.


http://lua-users.org/wiki/MetatableEvents

위 링크에는 사용법이 아니라 메타테이블 함수가 나열되어있는데,

사용법 링크는 http://lua-users.org/wiki/MetamethodsTutorial


나도 주워본걸로만 이해해서 잘은 모르지만 아는대로만 설명해볼게.


아래는 metatable설명임. 필요없으면 스킵해도 좋다.


lua metatable 설명

-ㅁㅁㅁㅁㅁㅁ----------------------- 스킵해도 됨 -----------

테이블 두개를 만들어두고

a={}, b={}

setmetatable(a,b) 이렇게 쓰면

a테이블은 평범한 테이블, b테이블은 일종의 class 원형기능의 일부처럼 사용할 수 있는거야.


class는 rpg에서 나오는 클래스 그거랑 거의 동의미라고 보면 됨.

lua에서 class는 새로 만들어진 table이나 다름없는데, class가 적용된 좀더 복잡한 데이터 집합은 대개 object라고 부르더라.

아무튼 object(개체)라고 부른다. 이 object가 할 수 있는 복잡한 일을 쉽게 복붙해서 카테고리처럼 만들어서 관리하기 쉽게 만든거임.

전사 클래스로 어떤 object를 만들고싶으면 테이블을 만들고,

거기에 전사클래스로써 필요한 데이터 항목과 함수들을 원형이 되는 테이블(Original)에서 복사해서 만들고,

다음에 setmetatable로 그 데이터항목을 lua의 기존문법에 반응하는 추가적인 함수세트를 집어넣어줌. (Metatable)

새로만든 전사놈은 같은 클래스끼리는 똑같은 기능을 갖춘 복제품(Clone)이 되는거임.


원래대로면 테이블 안에 어떤 함수를 실행하려면

a.run(arg)

이런식으로만 써야하는데,


lua 문법에 비교== 라던지 대입 = 라던지, 테이블 인덱스 늘리기 asdf[1] = a 라던지 이런 동작이 벌어질때 기본동작을 씹어버리고 metatable에 정의된 동작이 실행되도록 바꿔치기하는게 metatable임.

setmetatable(a,b)

이라면 이걸 class 처럼 쓰려면 a는 Clone이 되야하고, b는 기존문법 바꿔치기하는 함수들이 들어간 Metatable이 되야함.

a에는 자기 자신만의 데이터가 필요한데, 그건 또 다른 원형이 되는 테이블(Original)을 만들어서 거기서 deepcopy 같은걸 해와야함.


요약하면, metatable을 class처럼 쓰려면

Original (각 Clone의 개별데이터 디폴트값으로써, 여기엔 setmetatable을 안써도 되고, 원형으로써 초기값과 function() 형태로 사용하는 함수를 영구보관하면 되는것)

Metatable (이놈은 setmetatable의 두번째인수로만 항상 사용될 놈이고, http://lua-users.org/wiki/MetatableEvents 여기있는 것들로 내용을 채워넣으면 되는것)

이렇게 원형 테이블이 두개가 필요하고,

Clone 은 만든다음에 Original 내용을 복제해오고, setmetatable(Clone, Metatable)로 metatable로 등록을 해줘야함.


이렇게 만든다음에 메타테이블 확인하는 함수인 getmetatable을 써보면,

getmetatable(Original) 하면 nil 나오고

getmetatable(Metatable) 하면 nil 나오고

getmetatable(Clone) 하면 Metatable이 나오는거임.

-ㅁㅁㅁㅁㅁㅁ-----------------------


팩토리오 얘기로 돌아와서

https://lua-api.factorio.com/latest/Global.html

보면

Tables, but not meta tables; tables with metatables become plain tables when saved and loaded.

라는 내용이 있는데, tables with metatables 라고 부르는 놈이 getmetatable(table) 하면 nil이 아닌게 return되는거임.

그니까 저걸 호칭하길, "메타테이블이 있는 테이블"이라고 부르는거지.

global에는 저걸 저장하면 세이브할 때 그 setmetatable로 링크된 정보가 지워진다는 설명이 있는거다.

그니까 아무리해도 꼭 "메타테이블이 있는 테이블"을 global안에 저장하고 싶으면 on_load 이벤트 때마다 setmetatable을 다시 해줘야

멀티플레이 비동기화(desync)나 모드나 시나리오가 로드할 때마다 고장나는걸 막을 수 있어.


LuaEntity같은 기존 오브젝트도 사실 table with metatable 인데, 엄청난 예외로써 취급되서 global에 저장할 수 있다.


그럼 table index is nil 이 왜떴냐

라는 처음 얘기로 돌아와서, 이 에러를 띄우는건 LuaRemote임

https://lua-api.factorio.com/latest/LuaRemote.html

table[nil] 같은 테이블을 못불러온다고 그러는거임.

이게 가능한건 global의 어떤 table의 키값에 table with metatable이 들어가 있는거고, 그 table with metatable의 metatable 안에는 어떻게 호출되면 nil이 나오도록 하는게 있나봐.

lua는 javascript하곤 다르게 테이블의 key에도 테이블을 집어넣을 수 있는거 같더라고.

그리고 table with metatable는 LuaEntity같은 게임내 개체인거지.


이 LuaEntity가 destroy()라던가 die()라던가 뒤져서 없으면 어떤식으로 저장되는지 말해볼게.



이놈은 뒤졌어도 일부 데이터가 멀쩡히 살아있어. 게임 세이브할때 global안에 있어도 세이브도 되고, 로드도 됨.

개체의 레퍼런스가 살아있는거임. 완전히 지우는 방법은 모르겠음. 주기적으로 자동으로 지워지거나 하겠지. garbage처리 뭔가 있는듯하니까.

아니면 레퍼런스 자체에만 데이터가 있어서 레퍼런스를 저장할 곳이 아무데도 없으면 그때 지워지거나 할거같아.


죽은 개체는 metatable에 의해서 동작이 변경된 상태인데, 뒤져서 없어도 아래같이 동작한다.

죽은 개체 이름을 일단 Clone이라고 해봄.

저렇게 remote가 복사해오거나 어떻게 그냥 읽을 땐 nil이 되는듯 함. 살아있었으면 걍 가져온다. 아마 아무데도 local value라도 저장한 곳이 없으면 그때 nil이 되는거 같음. 그렇게 되면 메모리 뜯어보지 않는 이상 애초에 확인할 방법도 없겠지만. 뜯어 볼줄도 모름 ㅋㅋ

game.print같이 출력하는 함수안에서 호출하면 LuaEntity같이 개체 원형 이름을 뱉음

if Clone then... 같은 비교문에서 호출하면? nil이 아니라서 false로 처리가 안됨.

그래서 존나 번거롭지만, 레퍼런스 데이터가 살아있는데 뒤져서 없는 경우를 위해서

Clone.valid 라는 항목이 있음.

if Clone and Clone.valid then... (Clone이 존재한다면...) 처럼 .valid를 쓴 내용이 다른 사람 코드에 종종 보이는 이유.


난 이 구문 처음에 오류가 있는건줄 알았는데, and 동작을 보니까 그렇지가 않더라고.

난 첨에 이게 Clone이 완벽한 nil이면 테이블이 아니니까 nil의 ['valid']라는 index를 호출할 때 에러가 터질줄 알았는데,

lua는 앞에가 nil이고 뒤에가 and면 어차피 false일테니 뒤에를 읽지 않고, 넘어가더라?


이 구문을 완전히 뒤집으면

if not Clone or not Clone.valid then... (Clone이 존재하지 않는다면...)


viewimage.php?id=2bbcd332eac031a9&no=24b0d769e1d32ca73fec86fa11d02831f774ca47ac4dd7dcba669517d2fdc459940edbcc853bfaaf6876474e3cc7777da2355d097e13f7ef18ec4b6b9d69239bddfe73f8


아무튼 table의 key값에는 LuaObject를 집어넣으면 remote가 못읽네.

그리고 function이랑 userdata도 집어넣을 수 없다고 그러는데,

function은 맵 세이브할 때 데이터가 증발함. table에 붙어있던 metatable링크가 증발하듯이. 어찌해도 꼭 쓰고싶으면 on_load때마다 재등록이 필요.

userdata는 global에다 저장하면 아예 세이브도 못함. serialise를 못한다고 뜨면서 세이브도 못함.

근데 어차피 세이브 안되는 값들은 global에다 저장하지말고 일반 전역변수 (앞에 표기없이 그냥 변수선언) 에다 저장하는게 나을거 같은데...


viewimage.php?id=2bbcd332eac031a9&no=24b0d769e1d32ca73fec86fa11d02831f774ca47ac4dd7dcba669517d2fdc459940edbcc853bfaaf6876474e3cc7777da2355d097e13f7ef4bed4a6ccc3d219d30c07726


아무튼 remote.call이 못하고 에러띄우는놈들은 권장하는 global 테이블 사용방법이 아니기에 그런거 같다.

https://lua-api.factorio.com/latest/Global.html

애초에 여기에 nil, strings, numbers, booleans 같은거나 일반 테이블, LuaObject만 저장하라고 되어있으니...

근데 LuaObject를 key로써 쓰지말란말은 안보이는데, remote가 뒤진 LuaObject가 key로 쓰였을 때 복사를 못해오는거 보면 이것도 하면 안되는 행위에 들어가는거 같다.


그리고 마운틴 포트리스 시나리오는 하지말라는 이걸 하고있어서 모드 제작시에 엄청 좋은 샘플이 되었음 ㅋㅋㅋ 예외처리 재밌게 했다.


그래서 만든게 진단기능이지.

저거 정리 버튼 누르면 remote가 오류띄우는 항목을 싹 날려버린다. 날려버리고 뭘 날렸는지 기록도 남겨줌.

애초에 desync원인중에 하나가 global 테이블이 세이브되고 로드될 때 불일치되는게 원인 중 하나인데, 저걸로 싹 걸러서 보여줌.

괜찮지 않아?



-------------------------


그리고 0.2.0에 추가한 강려크한 기능.


모드 안에서 lua 코드 커맨드를 쓰는거임.


viewimage.php?id=2bbcd332eac031a9&no=24b0d769e1d32ca73fec86fa11d02831f774ca47ac4dd7dcba669517d2fdc459940edbcc853bfaaf6876474e3cc7777da2355d097e13f7ef1de7156e9d3973ca239a6c1d


base, core를 포함한 각 모드랑 현재 진행중인 맵(level)은 각자 샌드박스를 가지고있고 그안에 각자의 game, script, global 등등이 있음.

바닐라 상태에서도 base, core, level의 3개의 샌드박스가 돌아간다는 사실은 좀 충격이었음.

아예 base빼고 모드 만들어도 되는거아냐이거?? (겜 첨부터 새로만듦) 모드 설정에 비호환 모드에 base넣으면 될거같긴한데 ㅋㅋㅋ

근데 core 버전을 따오는 방법이 없어보이던데 이런건 어캐하나...


아무튼 기본상태에서 /c 같은 명령어써서 뭔가 실행하면 그건 level "모드"의 샌드박스 안에서 돌아감.

/g-c 는 모드의 샌드박스안에서 명령어가 실행되도록 해준다. 그냥쓰면 gvv모드 안에서 실행되고,

/g-c --[[모드이름]] 루아코드 이렇게 쓰면 해당 모드의 샌드박스 안에서 실행됨.

모드를 만들고있고, 모드안의 script.on_event 라던가 기타등등 해당 모드의 코드가 아니면 접근불가영역에 존재하는걸 게임중에 변경해보고 싶을 때 쓰는거임.

global이라는 표기를 쓰면 그것도 모드의 global이 되고.


만약 표기가 없는 전역변수를 선언해서 쓰고있다면 그것도 역시 각 모드따라감.

무표기 전역변수를 사용하면 안좋다는 식으로 내가 얘기를 적은적이 있는데, 저장이 안되니까 desync의 위험성과 로드할 때마다 고장날 위험성에 주의해서 잘 다룰 수 있으면 사용해도 되는 거임.

global로 저장이 안되는 변수는 그냥 쿨하게 무표기 전역변수로 만들고, 그 내용을 global안에 저장될 수 있는 형태로 찢어서 보관하고, on_load마다 다시 부활하게 하면 될듯.


/editor의 lua 스니펫 예제도 들어가있어.

lua 스니펫에서도 코드를 실행하면 level안에서 돌아가는데, 이걸 모드의 샌드박스로 옮겨서 돌리는 예제.



국산 시나리오나 모드 양산되었으면 좋겠다는 마음으로 만든 모드임. 국내 모더 늘어났으면 좋겠다.

바닐라 시나리오는 접근성도 좋아. 심심하면 뭐 하나 간단히 만들어서 사람모아서 해보면서 놀면 재밌음!


추천 비추천

2

고정닉 1

0

댓글 영역

전체 댓글 0
등록순정렬 기준선택
본문 보기

하단 갤러리 리스트 영역

왼쪽 컨텐츠 영역

갤러리 리스트 영역

갤러리 리스트
번호 말머리 제목 글쓴이 작성일 조회 추천
2863 설문 시세차익 부러워 부동산 보는 눈 배우고 싶은 스타는? 운영자 24/05/27 - -
2862 AD 희귀 정령 획득 기회! <아스달 연대기> 출석 이벤트 운영자 24/05/23 - -
26202 정보 [lua]모딩/시나리오의 이벤트 핸들러 사용법 ㅇㅇ(121.137) 20.09.21 477 0
25762 일반 [lua]시나리오나 모드 만드는 사람들 편집기 뭐씀? [1] ㅇㅇ(121.137) 20.09.14 134 0
25556 일반 [lua] localising Unknown key 회피하는거 만들었어 [9] ㅇㅇ(121.137) 20.09.12 179 1
25523 일반 [lua] 레시피 localised string 짜왔어 [12] ㅇㅇ(121.137) 20.09.11 139 0
25511 자랑 [lua] gvv와 이벤트추적 모드가 더 강해졌따 ㅇㅇ(121.137) 20.09.11 267 2
25486 일반 [lua] Recipe 정보 추출 [16] 이파갤로그로 이동합니다. 20.09.11 326 0
25182 일반 [lua]아 gvv 모드만들면서 바보짓 했다 ㅇㅇ(121.137) 20.09.08 109 0
정보 [lua]개발용 모드 gvv 업뎃 많이함. lua metatable설명 [7] ㅇㅇ(121.137) 20.09.07 530 2
24930 일반 [lua]오 만든 모드 피드백이 왔어 ㅇㅇ(121.137) 20.09.06 273 1
24877 정보 [lua]global 변수 보는 모드를 공개한다 [5] ㅇㅇ(121.137) 20.09.05 218 3
24847 일반 [lua]요새 만들고 있는것 [1] ㅇㅇ(121.137) 20.09.05 150 4
24013 일반 [lua]디버깅 툴 하나 만들었다 [3] ㅇㅇ(121.137) 20.08.30 880 8
23795 정보 [lua]이벤트 추적기 콘솔커맨드 버전 [2] ㅇㅇ(121.137) 20.08.28 243 2
23726 정보 [lua]모딩 일단 따라하기 - 4. 모드GUI템플릿, 로딩이벤트 ㅇㅇ(121.137) 20.08.28 458 4
23720 정보 [lua]모딩 일단 따라하기 - 3. GUI 만들기 연습 [3] ㅇㅇ(121.137) 20.08.28 505 5
23638 일반 [lua]타일 변경 추적하기 고찰 - 전력공급타일? [3] ㅇㅇ(121.137) 20.08.27 246 4
23615 정보 [lua]모딩 일단 따라하기 - 2. control.lua 예제 설명 [16] ㅇㅇ(121.137) 20.08.27 505 6
23583 정보 [lua]모딩 일단 따라하기 - 1 [17] ㅇㅇ(121.137) 20.08.27 1416 11
23396 일반 [lua] 말머리가 필요하다 [2] ㅇㅇ(121.137) 20.08.26 145 0
23313 정보 [lua]뭐야 멀티게임 일시정지보다 더 좋은게 있어 [8] ㅇㅇ(121.137) 20.08.25 2134 8

게시물은 1만 개 단위로 검색됩니다.

갤러리 내부 검색
제목+내용게시물 정렬 옵션

오른쪽 컨텐츠 영역

실시간 베스트

1/8

뉴스

디시미디어

디시이슈

1/2