ディカプリオかっけー。ファンでした何かください。

ネタバレ注意っすなぁ

テディがレディスになっていく過程が大部分なわけだけど

あえて俺はレディスこそ作られた妄想だといいたい

根拠なんてないけどもさ


人間は思い込みを正せない

この映画はテディが実はレディスでした

ほら錯覚ってすごいよねっていう構成になってるんだけども

もう一歩ひねって見てみると

テディが実はレディスで錯覚なのだっていうお話を見せられて

ホントにテディがレディスだと思っちゃってるの?

それが実は錯覚だったんだけどねー

のほうが話としては面白い

テディは実はレディスでしたという錯覚が実は錯覚でした

みたいなね

彼はホントは正常ですよ。でもね。思い込みは正せないでしょ?

うん。もうわけわかんねけどw


正常だと思って生きてきたのにある日突然

周りのみんなが揃いも揃って「病んでますね」と言う

そんな事いわれたら俺は病んでるのかと思っちゃうよね

いや俺は言われてはないよ?俺の話じゃないよ?


人間は思い込みを正せない

そして正常なのにロボトミーされてしまう


あ、でも俺まだこの映画見てないや

的錯覚でしたw



ちなみにファンなのは本当です・・

ネットワーク部分の抽象化2

前回、この同期するための情報を管理する同期クラスですが、これを便利につくってあげると
かなり通信自体が楽になるとおもいます。
ということでしたが、この部分をどう作るべきか。非常に難しいところです。


ここをまじめに丁寧に書くと結構膨大になります。本1冊余裕で書けそうなトピックです。
なので99%飛ばしますw
結論から言うとデザインパターンのProxyパターンを使います。
もう少し煮詰めるとCorbaとかDComとかが近いのかな。要するにリモートオブジェクトとその管理クラスです。
そしてその管理クラスが同期クラスになります。


具体的な流れでいうと、こんな感じです。


まずサーバーにスケルトンクラスを継承したプレーヤーキャラクタークラスのオブジェクトを作成します。
同期クラスはスケルトンクラスへの集約となっていて、同期クラスのオブジェクトは各クライアントごとにサーバー側に存在します。
これをサーバー同期クラスとしましょう。


これと同様にクライアント側にも管理クラスとして、クライアント同期クラスがあります。
あるプレーヤーキャラクタークラスのオブジェクトを、サーバー同期クラスのオブジェクトに追加すると
その情報がクライアント同期クラスに伝わり、クライアント同期クラスは
クライアント側にキャラクタークラスのオブジェクトのコピーを自動的に作成します。


このコピーオブジェクトは、スケルトンクラスではなく
スタブクラスというクライアント側のスケルトンクラスに対応するクラスを継承しているクラスのオブジェクトになります。


まさにCorbaとかのリモートオブジェクトのような仕組みですが
この仕組み全体について、フルスクラッチで自分でコーディングするため
用途は限定されますが、非常に軽量なリモートオブジェクトが作れるというメリットがあります。


そして最終的にはキャラクタークラスの各種Set関数の中に
同期を取るための通信処理を入れ込んでしまいます。


つまり

player_character.set_hitpoint(100);
client_socket.send(SET_HITPOINT);
client_socket.send(100);

ではなく

player_character.set_hitpoint(100);

void Player_character::set_hitpoint(unsigned long value)
{
//PLAYER_CHARACTER_SET_HITPOINTはこの関数を表現するID
client_socket.send(PLAYER_CHARACTER_SET_HITPOINT);
client_socket.send(100);
...


とすることでPlayer_characterの外からは通信を意識させないようにできます。
これは、このような簡単の例の場合には、余りありがたみが分かりませんが
実装が進んでいき、構造が複雑になればなるほど効果がでてくるものです。


このような仕組みを作ったとき、あるキャラクターの視界にあるキャラクターが入ったとしたら
お互いのサーバー同期クラスにお互いのキャラクターを追加登録(push_back)するだけで
あとは自動でデータをやり取りしてくれるようになります。
もちろん中では必死にデータの通信をしているのですが
このクラスを利用する側では通信を意識しないで作りこむ事が可能です。


ただし、この方式には適さないデータがある場合もあります。
この方式では、何かしらアクションがあった場合(例えばキャラクターのHitpointが変更された場合など)
サーバークライアント間のラグを問わず、そのままクライアントに流し込むだけになります。
これはHitpointであればあまり問題は起こりません。


ただし位置情報になると話が変わります。
サーバーが保持している位置情報も、各クライアントが保持している位置情報も
ネットワークにはラグがありますから、同時刻で別の位置情報です。
単にクライアントに流し込まれた位置情報で描画し
そのクライアントでその位置情報にめがけて攻撃しても
サーバーで判定される頃にはその位置には誰もいないといった矛盾が起こります。


もちろんこれはゲーム次第です。
カードゲームであればまったく問題になりませんし
ターン制の戦闘を採用しているゲームでも問題ありません。
ターゲット固定できるようなゲームでも問題はあまり?おきません。
(後ろから攻撃したら倍のダメージになるという仕様があれば問題がおきますが・・・)


この辺はゲーム次第、データ次第でこのリモートオブジェクトの仕組みを使うかどうかを検討してください。
また、また改めて断っておきますが、ここまで説明してきて
この問題についての正解は残念ながらないと思います。
この方式が幅広く比較的ベターという(風に私が思っている)だけです。


で、肝心の位置情報はどうやってやり取りすればいいのってのは
また次回にでも。
相変わらず分かりにくい文章ですがw

ちょっとした反抗期。オブジェクト指向のここが嫌いだ。(おちなんてないいい)

わたしはオブジェクト指向と呼ばれるものが比較的好きなほうじゃないかな。

でも嫌いなものもいくつかある。

まず第一に継承。これはきらい。

覚えたてのころなんかは継承しまくって何度も痛い目を見たのでvirtualという単語を見ると胸がドキドキする。

特にデストラクタについているvirtualと=0を見たときはストレスマッハだ。=0を消したくなる。

まぁでも継承はうまく使ってあげればそれなりに付き合っていける。

もっと嫌いなのはカプセル化

これはもうなんかダメ。だってそもそもclassが嫌い。

デフォルトでprivateなclassよりもpublicなstructがいい。

何もなければ隠しちゃうとか陰湿すぎる。オープン人が私は好きだ。

多分こんなこと言うと教科書のごとく

いろんなところで見えちゃって万が一書き換えられたらどうするの?とか突っ込まれるかもしれない。

でも、私は、たとえばstructの中にメンバ変数が定義されてたとして

いきなりそのメンバにアクセスするようなコードは書いたりしない。

見た瞬間これは罠なんじゃないか?と疑ってかかる。

今まで痛い思いしてたら大体そう。structの変数なんて罠以外の何者でもない。

自分が書いたstructのメンバ変数を、仮に端からprivateに置き換えてもコンパイルエラーはほとんどおきない。

罠には触れたくないからだ。

だったらclassで書けよって?

ごもっともです。

後ひとつ、わたしが日ごろ懐疑的に思うキーワード。ブラックボックス

よく例として見かけるのが洗濯機。

全自動のボタン押せば、中身の構造が分からなくても洗濯してくれるから便利でしょ

と。

たしかに構造しらなくても使えるのは便利。うん、便利。

でもね。わたしはこれがどうしても洗濯機に見えない。分からない。

中身も知らないんだけど、外見も分からないんだよ。

もし、自分が過去に書いたコード、特にヘッダがぱっと見で何をしているのか分からないなら

ある意味もうブラックボックス化にかなり成功しています。

ただしブラックボックスなのは全体です。

そんなコードを再利用したら大変。

結局細部の構造を調べさせられることになる。余計な手間が増えただけになる。

せめて洗濯機に見えないコードは、『これは洗濯機です。』と書いておくべきだ。

ただ、万が一、未来の自分に対する挑戦状を送りたいなら、これは絶好の機会になりそうだけど。

ConnectEx,AcceptEx


MSDNからの引用

When the ConnectEx function successfully completes, socket handle s can be passed to only the following functions:

    * ReadFile
    * WriteFile
    * send or WSASend
    * recv or WSARecv
    * TransmitFile
    * closesocket


あれれ・・・?shutdownは?

SD_SENDしたいんだけど・・どうなってんのこれ

AcceptExもshutdown使えないようです。

試しにやってみたらWSAENOTCONN(10057)


つ、つながってないって??・・え、何?このデータ

いっぱいデータ送受信できてるんだけどおお><


ConnectもAcceptも完了ポートしたかったんだけどなぁ・・・

今回は素直にWSAEventSelectかなぁ・・・



追記

Acceptするソケットはshutdownいらなかったね。ってことは完了ポートできそー

ちょっとがっかりだったけど、希望が見えてきたヽ(´ー`)ノ


さらに追記

ちょっと調べてみるとAccept完了後

setsockopt(server_socket,SOL_SOCKET,SO_UPDATE_ACCEPT_CONTEXT,(char*)&listen_socket,sizeof(listen_socket))==SOCKET_ERROR


って感じで新しいサーバーソケットにListen用ソケットのオプションをコピーしてやるとshutdown可能でした。

Σ(゚Д゚;≡;゚д℃(゚д゚)エ?キタノ?

ちなみにConnectExのほうはまだやってないのでわかりませんがSO_UPDATE_CONNECT_CONTEXTもあるみたいなので

できそーじゃないかなぁ

どのソケットからこぴるか謎ですが・・・

ConnectExもできました。

err = setsockopt( s, 
  SOL_SOCKET, 
  SO_UPDATE_CONNECT_CONTEXT, 
  NULL, 
  0 );


こんな風にやるみたいです