欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Lua游戲開(kāi)發(fā)教程之時(shí)區(qū)問(wèn)題詳解

 更新時(shí)間:2018年09月16日 08:42:11   作者:meteoric_cry  
時(shí)間顯示問(wèn)題說(shuō)白了就是時(shí)差問(wèn)題,這篇文章主要給大家介紹了關(guān)于Lua游戲開(kāi)發(fā)教程之時(shí)區(qū)問(wèn)題的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

前言

什么是Lua?

Lua 是一個(gè)小巧的腳本語(yǔ)言,巴西里約熱內(nèi)盧天主教大學(xué)里的一個(gè)研究小組于1993年開(kāi)發(fā),其設(shè)計(jì)目的是為了嵌入應(yīng)用程序中,從而為應(yīng)用程序提供靈活的擴(kuò)展和定制功能。Lua由標(biāo)準(zhǔn)C編寫(xiě)而成,幾乎在所有操作系統(tǒng)和平臺(tái)上都可以編譯,運(yùn)行。一個(gè)完整的Lua解釋器不過(guò)200k,在目前所有腳本引擎中,Lua的速度是最快的。這一切都決定了Lua是作為嵌入式腳本的最佳選擇。相比Python和Per的內(nèi)核,Lua的內(nèi)核小于120KB,而Python的內(nèi)核大約860KB,Perl的內(nèi)核大約1.1MB。Lua語(yǔ)言支持面向?qū)ο缶幊毯秃瘮?shù)式編程,它提供了一個(gè)通用類(lèi)型的表table,可以實(shí)現(xiàn)數(shù)組、哈希表、集合、對(duì)象的功能。Lua支持協(xié)同進(jìn)程機(jī)制。作為一門(mén)可擴(kuò)展的語(yǔ)言,Lua提供簡(jiǎn)單而穩(wěn)定的交互接口,如Lua和C程序可通過(guò)一個(gè)堆棧交換數(shù)據(jù),這使得Lua語(yǔ)言可以快速地和其它語(yǔ)言實(shí)現(xiàn)整合。

總體來(lái)說(shuō),Lua語(yǔ)言具備以下優(yōu)點(diǎn):

(1)語(yǔ)言?xún)?yōu)美、輕巧

(2)性能優(yōu)良、速度快

(3)可擴(kuò)展性強(qiáng)。

正因?yàn)長(zhǎng)ua語(yǔ)言具備了這樣的特點(diǎn),使得它能和游戲開(kāi)發(fā)領(lǐng)域的需求完美地結(jié)合起來(lái),因?yàn)槲覀冃枰@樣的一門(mén)語(yǔ)言,它能夠和C/C++進(jìn)行完美地交互,因?yàn)槲覀冃枰鼘?duì)底層進(jìn)行封裝。它需要足夠地簡(jiǎn)單,因?yàn)槲覀冃枰?jiǎn)單、靈活、快速地編寫(xiě)代碼。那么顯然Lua就是我們一直在尋找地這種語(yǔ)言。

目前大部分游戲都采用了Lua語(yǔ)言進(jìn)行功能開(kāi)發(fā),在進(jìn)行多語(yǔ)種發(fā)行的時(shí)候就會(huì)遇到時(shí)區(qū)顯示的問(wèn)題。以韓國(guó)版本為例,場(chǎng)景如下:

1、服務(wù)器處于固定的位置,比如放在首爾機(jī)房;

2、玩家所處的位置不確定,可能在韓國(guó),或者是出差在其它國(guó)家或地區(qū);

需求:

無(wú)論在哪個(gè)國(guó)家或地區(qū),統(tǒng)一顯示服務(wù)器的當(dāng)前時(shí)間。在PC上查看,即便在國(guó)內(nèi)測(cè)試的時(shí)候也顯示韓國(guó)首爾的時(shí)間(比北京時(shí)間快1個(gè)小時(shí))。

實(shí)現(xiàn):

-- 北京時(shí)間
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)

關(guān)注是這個(gè)方法: os.date("!*t", now),其中以!為關(guān)鍵。

lua 源碼, loslib.c Line 283 行

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

從源碼可以看到 ! 調(diào)用了

#define l_gmtime(t,r)  gmtime_r(t,r)

gmtime_r 函數(shù)是標(biāo)準(zhǔn)的POSIX函數(shù),它是線程安全的,將日歷時(shí)間轉(zhuǎn)換為用UTC時(shí)間表示的時(shí)間。

注:UTC —— 協(xié)調(diào)世界時(shí),又稱(chēng)世界統(tǒng)一時(shí)間、世界標(biāo)準(zhǔn)時(shí)間

也就是說(shuō) “!*t” 得到的是一個(gè) UTC 時(shí)間,為0度的經(jīng)線(子午線),亦稱(chēng)本初子午線,通常將它與GMT視作等同(但是UTC更為科學(xué)和精確)。

 

首爾位于東9區(qū),所以實(shí)際的時(shí)間應(yīng)該是 UTC + 9,9就是時(shí)區(qū)差 —— 9個(gè)小時(shí)。北京位于東8區(qū),即 UTC + 8。

如何保證游戲內(nèi)全部統(tǒng)一為服務(wù)器的時(shí)間呢?

服務(wù)器需要返回給客戶(hù)端當(dāng)前的時(shí)區(qū)的差值,比如韓國(guó)就返回 9,國(guó)內(nèi)就返回 8,越南返回 7,北美返回 –16,記為 serverTimeZone。

服務(wù)端返回當(dāng)前服務(wù)器時(shí)間serverTime(即首爾當(dāng)前時(shí)間),我們只需要將服務(wù)器時(shí)間轉(zhuǎn)為 UTC 的時(shí)間,然后再加上 serverTimeZone即可。

os.time(os.date("!*t", serverTime)) + serverTimeZone * 3600

這樣無(wú)論在哪個(gè)地區(qū)或國(guó)家,都將顯示首爾的時(shí)候,與服務(wù)器顯示的時(shí)間就同步上了。

為什么要一直顯示服務(wù)器的時(shí)間呢?

游戲中有很多功能是有時(shí)間限制的,比如運(yùn)營(yíng)活動(dòng),或者功能開(kāi)啟。如果用本地時(shí)間就不好控制,統(tǒng)一用服務(wù)器時(shí)間避免了很多問(wèn)題。

可是也容易遇到一個(gè)坑,運(yùn)營(yíng)配置的活動(dòng)時(shí)間都是針對(duì)當(dāng)前服務(wù)器的時(shí)間,例如某個(gè)活動(dòng)的截止時(shí)間是:2018-10-08 00:00:00,游戲需要顯示活動(dòng)截止倒計(jì)時(shí)。

通常的做法: ployEndTime – serverTime,得到一個(gè)秒數(shù),然后將秒轉(zhuǎn)成:xx天xx小時(shí)xx分xx秒

serverTime 是固定的,可是ployEndTime就容易出錯(cuò),為什么?

serverTime 是在東9區(qū) —— 首爾的時(shí)間,而 os.time({year=…}) 是根據(jù)本地時(shí)間來(lái)算時(shí)間的,這中間就存在問(wèn)題。有一個(gè)時(shí)差的問(wèn)題,之前計(jì)算一直用的是serverTimeZone —— 一個(gè)固定值,而我當(dāng)前處于地區(qū)或國(guó)家,它相對(duì)于UTC的時(shí)區(qū)不確定的,怎么辦?

用 (currTimeZone – serverTimeZone) * 3600 / 秒,os.time()之后再加上這個(gè)時(shí)區(qū)差就是首爾當(dāng)前的時(shí)間戳了。國(guó)內(nèi)東8 - 東9  = -1,也就是要減去一個(gè)1時(shí)區(qū),最終將得到首爾地區(qū)的時(shí)間戳,再減去 serverTime 就是剩下的秒數(shù)了,然后將它轉(zhuǎn)為 xx 天 xx 小時(shí) xx 分 xx 秒。

最后小結(jié)一下:

1)os.time({year=xx}),這個(gè)時(shí)間算出來(lái)的是針對(duì)當(dāng)前所處時(shí)區(qū)的那個(gè)時(shí)間戳。

2)os.date(“!*t”, 時(shí)間戳) 得到的是UTC(時(shí)區(qū)為0)的時(shí)間戳。

3)獲取當(dāng)前時(shí)區(qū)的值,可以通過(guò)文章開(kāi)頭的 getTimeZone 方法

4)想顯示固定時(shí)區(qū)的時(shí)間(例如無(wú)論在哪都顯示服務(wù)器的時(shí)間),只需要將(服務(wù)器)時(shí)間戳(秒),通過(guò)第2步的方法,得到 UTC 再加上固定的時(shí)區(qū)差

5)計(jì)算倒計(jì)時(shí)的時(shí)候,需要考慮到 os.time 是取當(dāng)前時(shí)區(qū),需要再將當(dāng)前時(shí)區(qū)減去目標(biāo)時(shí)區(qū),再計(jì)劃時(shí)間戳

6)夏令時(shí),本身已經(jīng)撥快了一個(gè)小時(shí),當(dāng)需要顯示為固定時(shí)區(qū)的時(shí)間,則需要減去一個(gè)小時(shí)

總結(jié)

以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問(wèn)大家可以留言交流,謝謝大家對(duì)腳本之家的支持。

相關(guān)文章

  • Lua協(xié)同程序(COROUTINE)運(yùn)行步驟分解

    Lua協(xié)同程序(COROUTINE)運(yùn)行步驟分解

    這篇文章主要介紹了Lua協(xié)同程序(COROUTINE)運(yùn)行步驟分解,本文著重分解協(xié)同程序的運(yùn)行步驟,需要的朋友可以參考下
    2015-01-01
  • Lua中string.lower()使用指南

    Lua中string.lower()使用指南

    這篇文章主要介紹了Lua中操作字符串的基本方法整理,是Lua入門(mén)學(xué)習(xí)中的基礎(chǔ)知識(shí),需要的朋友可以參考下
    2016-08-08
  • 安裝Nginx+Lua開(kāi)發(fā)環(huán)境

    安裝Nginx+Lua開(kāi)發(fā)環(huán)境

    本文主要詳細(xì)介紹了安裝Nginx+Lua開(kāi)發(fā)環(huán)境的過(guò)程以及nginx+lua的配置,十分的詳盡,這里推薦給小伙伴們。
    2015-02-02
  • 詳解Lua中if ... else語(yǔ)句的使用方法

    詳解Lua中if ... else語(yǔ)句的使用方法

    這篇文章主要介紹了詳解Lua中if ... else語(yǔ)句的使用方法,是Lua入門(mén)學(xué)習(xí)中的基礎(chǔ)知識(shí),需要的朋友可以參考下
    2015-05-05
  • 實(shí)現(xiàn)Lua中數(shù)據(jù)類(lèi)型的源碼分享

    實(shí)現(xiàn)Lua中數(shù)據(jù)類(lèi)型的源碼分享

    在Lua中有8種基礎(chǔ)類(lèi)型,像其他動(dòng)態(tài)語(yǔ)言一樣,在語(yǔ)言中沒(méi)有類(lèi)型定義的語(yǔ)法,每個(gè)值都攜帶了它自身的類(lèi)型信息。下面我們就來(lái)嘗試通過(guò)Lua 5.2.1的源碼來(lái)看類(lèi)型的實(shí)現(xiàn)
    2015-04-04
  • Lua進(jìn)階教程之閉包函數(shù)、元表實(shí)例介紹

    Lua進(jìn)階教程之閉包函數(shù)、元表實(shí)例介紹

    這篇文章主要介紹了Lua進(jìn)階教程之閉包函數(shù)、元表實(shí)例介紹,本文詳細(xì)講解了Lua的閉包函數(shù)和元表,并同時(shí)和C++做了比較,需要的朋友可以參考下
    2014-09-09
  • Lua中的模塊與module函數(shù)詳解

    Lua中的模塊與module函數(shù)詳解

    這篇文章主要介紹了Lua中的模塊與module函數(shù)詳解,本文講解了編寫(xiě)一個(gè)簡(jiǎn)單的模塊、避免修改模塊名的方法、模塊名參數(shù)等內(nèi)容,需要的朋友可以參考下
    2014-09-09
  • Lua中獲取table長(zhǎng)度的方法

    Lua中獲取table長(zhǎng)度的方法

    這篇文章主要介紹了Lua中獲取table長(zhǎng)度的方法,本文用多個(gè)實(shí)例講解多種情況下獲取Table長(zhǎng)度的方法,需要的朋友可以參考下
    2015-04-04
  • Lua性能優(yōu)化技巧(四):關(guān)于字符串

    Lua性能優(yōu)化技巧(四):關(guān)于字符串

    這篇文章主要介紹了Lua性能優(yōu)化技巧(四):關(guān)于字符串,本文講解了關(guān)于字符串的一些優(yōu)化技巧,需要的朋友可以參考下
    2015-04-04
  • Lua中的閉包小結(jié)

    Lua中的閉包小結(jié)

    這篇文章主要介紹了Lua中的閉包小結(jié),本文對(duì)閉包的概念做了講解,同時(shí)給出閉包代碼示例,需要的朋友可以參考下
    2014-09-09

最新評(píng)論