前言
什么是Lua?
Lua 是一個小巧的腳本語言,巴西里約熱內盧天主教大學里的一個研究小組于1993年開發,其設計目的是為了嵌入應用程序中,從而為應用程序提供靈活的擴展和定制功能。Lua由標準C編寫而成,幾乎在所有操作系統和平臺上都可以編譯,運行。一個完整的Lua解釋器不過200k,在目前所有腳本引擎中,Lua的速度是最快的。這一切都決定了Lua是作為嵌入式腳本的最佳選擇。相比Python和Per的內核,Lua的內核小于120KB,而Python的內核大約860KB,Perl的內核大約1.1MB。Lua語言支持面向對象編程和函數式編程,它提供了一個通用類型的表table,可以實現數組、哈希表、集合、對象的功能。Lua支持協同進程機制。作為一門可擴展的語言,Lua提供簡單而穩定的交互接口,如Lua和C程序可通過一個堆棧交換數據,這使得Lua語言可以快速地和其它語言實現整合。
總體來說,Lua語言具備以下優點:
(1)語言優美、輕巧
(2)性能優良、速度快
(3)可擴展性強。
正因為Lua語言具備了這樣的特點,使得它能和游戲開發領域的需求完美地結合起來,因為我們需要這樣的一門語言,它能夠和C/C++進行完美地交互,因為我們需要它對底層進行封裝。它需要足夠地簡單,因為我們需要簡單、靈活、快速地編寫代碼。那么顯然Lua就是我們一直在尋找地這種語言。
目前大部分游戲都采用了Lua語言進行功能開發,在進行多語種發行的時候就會遇到時區顯示的問題。以韓國版本為例,場景如下:
1、服務器處于固定的位置,比如放在首爾機房;
2、玩家所處的位置不確定,可能在韓國,或者是出差在其它國家或地區;
需求:
無論在哪個國家或地區,統一顯示服務器的當前時間。在PC上查看,即便在國內測試的時候也顯示韓國首爾的時間(比北京時間快1個小時)。
實現:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
-- 北京時間 local serverTime = 1536722753 -- 2018/09/12 11:25 function getTimeZone() local now = os. time () return os. difftime (now, os. time (os.date( "!*t" , now))) end -- 8 hour * 3600 seconds = 28800 seconds local timeZone = getTimeZone()/ 3600 print( "timeZone : " .. timeZone) local timeInterval = os. time (os.date( "!*t" , serverTime)) + timeZone * 3600 + (os.date( "*t" , time ).isdst and -1 or 0) * 3600 local timeTable = os.date( "*t" , timeInterval) --[[ for k, v in pairs(timeTable) do print(k .. ":" .. tostring(v)) end ]] print(timeTable.year .. "/" .. timeTable.month .. "/" .. timeTable.day .. " " .. timeTable.hour .. ":" .. timeTable.min .. ":" .. timeTable.sec) |
關注是這個方法: os.date("!*t", now),其中以!為關鍵。
lua 源碼, loslib.c Line 283 行
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
static int os_date (lua_State *L) { size_t slen; const char *s = luaL_optlstring(L, 1, "%c" , &slen); time_t t = luaL_opt(L, l_checktime, 2, time (NULL)); const char *se = s + slen; /* 's' end */ struct tm tmr, *stm; if (*s == '!' ) { /* UTC? */ stm = l_gmtime(&t, &tmr); s++; /* skip '!' */ } else stm = l_localtime(&t, &tmr); if (stm == NULL) /* invalid date? */ luaL_error(L, "time result cannot be represented in this installation" ); if ( strcmp (s, "*t" ) == 0) { lua_createtable(L, 0, 9); /* 9 = number of fields */ setallfields(L, stm); } else { char cc[4]; /* buffer for individual conversion specifiers */ luaL_Buffer b; cc[0] = '%' ; luaL_buffinit(L, &b); while (s < se) { if (*s != '%' ) /* not a conversion specifier? */ luaL_addchar(&b, *s++); else { size_t reslen; char *buff = luaL_prepbuffsize(&b, SIZETIMEFMT); s++; /* skip '%' */ s = checkoption(L, s, se - s, cc + 1); /* copy specifier to 'cc' */ reslen = strftime (buff, SIZETIMEFMT, cc, stm); luaL_addsize(&b, reslen); } } luaL_pushresult(&b); } return 1; } |
從源碼可以看到 ! 調用了
1
|
#define l_gmtime(t,r) gmtime_r(t,r) |
gmtime_r 函數是標準的POSIX函數,它是線程安全的,將日歷時間轉換為用UTC時間表示的時間。
注:UTC —— 協調世界時,又稱世界統一時間、世界標準時間
也就是說 “!*t” 得到的是一個 UTC 時間,為0度的經線(子午線),亦稱本初子午線,通常將它與GMT視作等同(但是UTC更為科學和精確)。
首爾位于東9區,所以實際的時間應該是 UTC + 9,9就是時區差 —— 9個小時。北京位于東8區,即 UTC + 8。
如何保證游戲內全部統一為服務器的時間呢?
服務器需要返回給客戶端當前的時區的差值,比如韓國就返回 9,國內就返回 8,越南返回 7,北美返回 –16,記為 serverTimeZone。
服務端返回當前服務器時間serverTime(即首爾當前時間),我們只需要將服務器時間轉為 UTC 的時間,然后再加上 serverTimeZone即可。
1
|
os. time (os.date( "!*t" , serverTime)) + serverTimeZone * 3600 |
這樣無論在哪個地區或國家,都將顯示首爾的時候,與服務器顯示的時間就同步上了。
為什么要一直顯示服務器的時間呢?
游戲中有很多功能是有時間限制的,比如運營活動,或者功能開啟。如果用本地時間就不好控制,統一用服務器時間避免了很多問題。
可是也容易遇到一個坑,運營配置的活動時間都是針對當前服務器的時間,例如某個活動的截止時間是:2018-10-08 00:00:00,游戲需要顯示活動截止倒計時。
通常的做法: ployEndTime – serverTime,得到一個秒數,然后將秒轉成:xx天xx小時xx分xx秒
serverTime 是固定的,可是ployEndTime就容易出錯,為什么?
serverTime 是在東9區 —— 首爾的時間,而 os.time({year=…}) 是根據本地時間來算時間的,這中間就存在問題。有一個時差的問題,之前計算一直用的是serverTimeZone —— 一個固定值,而我當前處于地區或國家,它相對于UTC的時區不確定的,怎么辦?
用 (currTimeZone – serverTimeZone) * 3600 / 秒,os.time()之后再加上這個時區差就是首爾當前的時間戳了。國內東8 - 東9 = -1,也就是要減去一個1時區,最終將得到首爾地區的時間戳,再減去 serverTime 就是剩下的秒數了,然后將它轉為 xx 天 xx 小時 xx 分 xx 秒。
最后小結一下:
1)os.time({year=xx}),這個時間算出來的是針對當前所處時區的那個時間戳。
2)os.date(“!*t”, 時間戳) 得到的是UTC(時區為0)的時間戳。
3)獲取當前時區的值,可以通過文章開頭的 getTimeZone 方法
4)想顯示固定時區的時間(例如無論在哪都顯示服務器的時間),只需要將(服務器)時間戳(秒),通過第2步的方法,得到 UTC 再加上固定的時區差
5)計算倒計時的時候,需要考慮到 os.time 是取當前時區,需要再將當前時區減去目標時區,再計劃時間戳
6)夏令時,本身已經撥快了一個小時,當需要顯示為固定時區的時間,則需要減去一個小時
總結
以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對服務器之家的支持。
原文鏈接:http://www.cnblogs.com/meteoric_cry/p/9637040.html