1. ホーム
  2. スクリプト・コラム
  3. ルア

Luaゲーム開発チュートリアル - タイムゾーンの問題

2022-01-06 14:41:33

前置き

Luaとは何ですか?

Luaは、1993年にブラジルのリオデジャネイロ・カトリック大学の研究グループが開発した小規模なスクリプト言語で、アプリケーションに組み込んで拡張やカスタマイズを柔軟に行えるように設計されています。Luaは標準C言語で書かれており、ほぼ全てのOSやプラットフォームでコンパイル、実行することができます。Luaの完全なインタプリタはわずか200kであり、Luaは現在利用可能な全てのスクリプトエンジンの中で最も高速です。これらのことから、Luaは組み込み用スクリプトとして最適です。PythonやPerのカーネルと比較すると、Pythonのカーネルが約860KB、Perlのカーネルが約1.1MBなのに対し、Luaのカーネルは120KB以下です。Lua言語はオブジェクト指向プログラミングと関数型プログラミングをサポートし、配列、ハッシュテーブル、コレクション、オブジェクトを実装できる汎用型のタブレットを提供します。Luaはコプロセスメカニズムをサポートしています。Luaは拡張可能な言語として、LuaとCプログラム間でデータを交換するためのスタックなど、シンプルで安定したインタラクションインタフェースを提供しており、他の言語との統合を迅速に行うことができます。

全体として、Lua言語には以下のような利点があります。

(1) 美しく、軽量な言語

(2) 優れた性能と速度

(3) 高いスケーラビリティ

これらの特徴から、Luaはゲーム開発のニーズにぴったりです。なぜなら、C/C++と完璧に相互作用する言語が必要であり、基礎となるレイヤーをカプセル化する必要があるからです。また、シンプルで柔軟性があり、素早くコードを書く必要があるため、シンプルであることも必要でした。ですから、Luaは私たちが探し求めていた言語であることは明らかです。

現在、ほとんどのゲームでLuaを使った機能開発が行われていますが、多言語で配信する場合、タイムゾーンの表示という問題にぶつかります。韓国版を例にとると、次のようなシナリオになります。

1. サーバーがソウルのサーバールームなど、固定された場所にある。

2.プレイヤーは、韓国国内、または他の国や地域への旅行など、不確かな場所にいる。

必要条件

国や地域に関係なく、サーバーの現在時刻を一律に表示する。PCで見た場合、中国でテストしても韓国ソウルの時間(北京時間より1時間早い)を表示する。

実装しています。

-- Beijing time
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 hours * 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 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;
}

ソースコードからわかるように、!

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

gmtime_r 関数は、スレッドセーフで、カレンダーの時刻を UTC 時刻で表される時刻に変換する POSIX 標準関数である。

注:UTC -- 協定世界時、世界統一時、世界標準時としても知られています。

つまり、"! *t"は、本初子午線として知られる経度0度(子午線)のUTC時刻を取得し、通常GMTと同等に扱われます(しかしUTCはより科学的で正確です)。

[...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...] [...]