6 2014 Deskull rearranged comment for Doxygen.
17 #ifdef HAVE_SYS_TIME_H
25 #elif defined(MACINTOSH)
26 #include <OpenTransport.h>
27 #include <OpenTptInternet.h>
29 #include <sys/types.h>
30 #include <sys/socket.h>
31 #include <netinet/in.h>
33 #include <arpa/inet.h>
39 #define MAX_HOSTNAME 256
42 #define RINGBUF_SIZE 1024*1024
43 #define FRESH_QUEUE_SIZE 4096
47 #define WAIT 100*1000 /* ブラウズ側のウエイト(us単位) */
49 #define DEFAULT_DELAY 50
50 #define RECVBUF_SIZE 1024
52 static long epoch_time; /* バッファ開始時刻 */
53 static int browse_delay; /* 表示するまでの時間(100ms単位)(この間にラグを吸収する) */
55 static int sd; /* ソケットのファイルディスクリプタ */
56 static long time_diff; /* プレイ側との時間のずれ(これを見ながらディレイを調整していく) */
57 static int server_port;
58 static GAME_TEXT server_name[MAX_HOSTNAME];
62 static int movie_mode;
66 #define close closesocket
70 static InetSvcRef inet_services = nil;
71 static EndpointRef ep = kOTInvalidEndpointRef;
74 /* 描画する時刻を覚えておくキュー構造体 */
77 int time[FRESH_QUEUE_SIZE];
93 int recv(int s, char *buffer, size_t buflen, int flags)
96 int n = OTRcv(ep, (void *) buffer, buflen, &junkFlags);
106 static errr (*old_xtra_hook)(int n, int v);
107 static errr (*old_curs_hook)(int x, int y);
108 static errr (*old_bigcurs_hook)(int x, int y);
109 static errr (*old_wipe_hook)(int x, int y, int n);
110 static errr (*old_text_hook)(int x, int y, int n, TERM_COLOR a, concptr s);
112 static void disable_chuukei_server(void)
114 term *t = angband_term[0];
116 chuukei_server = FALSE;
118 t->xtra_hook = old_xtra_hook;
119 t->curs_hook = old_curs_hook;
120 t->bigcurs_hook = old_bigcurs_hook;
121 t->wipe_hook = old_wipe_hook;
122 t->text_hook = old_text_hook;
125 /* ANSI Cによればstatic変数は0で初期化されるが一応初期化する */
126 static errr init_buffer(void)
128 fresh_queue.next = fresh_queue.tail = 0;
129 ring.wptr = ring.rptr = ring.inlen = 0;
130 fresh_queue.time[0] = 0;
131 ring.buf = malloc(RINGBUF_SIZE);
132 if (ring.buf == NULL) return (-1);
137 /* 現在の時間を100ms単位で取得する */
138 static long get_current_time(void)
141 return timeGetTime() / 100;
142 #elif defined(MACINTOSH)
146 gettimeofday(&tv, NULL);
148 return (tv.tv_sec * 10 + tv.tv_usec / 100000);
153 /* リングバッファ構造体に buf の内容を加える */
154 static errr insert_ringbuf(char *buf)
157 len = strlen(buf) + 1; /* +1は終端文字分 */
161 fd_write(movie_fd, buf, len);
163 if (!chuukei_server) return 0;
170 if (ring.inlen + len >= RINGBUF_SIZE)
173 if (chuukei_server) disable_chuukei_server();
174 else chuukei_client = FALSE;
176 prt("送受信バッファが溢れました。サーバとの接続を切断します。", 0, 0);
185 if (ring.wptr + len < RINGBUF_SIZE)
187 memcpy(ring.buf + ring.wptr, buf, len);
190 /* バッファの終端までに収まらない(ピッタリ収まる場合も含む) */
193 int head = RINGBUF_SIZE - ring.wptr; /* 前半 */
194 int tail = len - head; /* 後半 */
196 memcpy(ring.buf + ring.wptr, buf, head);
197 memcpy(ring.buf, buf + head, tail);
208 void flush_ringbuf(void)
214 if (!chuukei_server) return;
216 if (ring.inlen == 0) return;
231 /* ソケットにデータを書き込めるかどうか調べる */
232 select(sd+1, (fd_set *)NULL, &tmp_fdset, (fd_set *)NULL, &tv);
235 if (FD_ISSET(sd, &tmp_fdset) == 0) break;
237 result = send(sd, ring.buf + ring.rptr, ((ring.wptr > ring.rptr ) ? ring.wptr : RINGBUF_SIZE) - ring.rptr, 0);
242 if (chuukei_server) disable_chuukei_server();
244 prt("サーバとの接続が切断されました。", 0, 0);
252 ring.inlen -= result;
254 if (ring.rptr == RINGBUF_SIZE) ring.rptr = 0;
255 if (ring.inlen == 0) break;
258 if (!chuukei_server) return;
260 if (ring.inlen == 0) return;
266 /* ソケットにデータを書き込めるかどうか調べる */
267 result = OTSnd(ep, ring.buf + ring.rptr, ((ring.wptr > ring.rptr ) ? ring.wptr : RINGBUF_SIZE) - ring.rptr, 0);
272 if (chuukei_server) disable_chuukei_server();
274 prt("サーバとの接続が切断されました。", 0, 0);
282 ring.inlen -= result;
284 if (ring.rptr == RINGBUF_SIZE) ring.rptr = 0;
285 if (ring.inlen == 0) break;
291 static int read_chuukei_prf(concptr prf_name)
296 path_build(buf, sizeof(buf), ANGBAND_DIR_XTRA, prf_name);
297 fp = my_fopen(buf, "r");
299 if (!fp) return (-1);
304 browse_delay = DEFAULT_DELAY;
306 while (0 == my_fgets(fp, buf, sizeof(buf)))
309 if (!strncmp(buf, "server:", 7))
311 strncpy(server_name, buf + 7, MAX_HOSTNAME - 1);
312 server_name[MAX_HOSTNAME - 1] = '\0';
316 if (!strncmp(buf, "port:", 5))
318 server_port = atoi(buf + 5);
322 if (!strncmp(buf, "delay:", 6))
324 browse_delay = atoi(buf + 6);
331 if (server_port == -1 || server_name[0] == 0) return (-1);
336 int connect_chuukei_server(char *prf_name)
342 WORD wVersionRequested = (WORD) (( 1) | ( 1 << 8));
345 struct sockaddr_in ask;
348 if (read_chuukei_prf(prf_name) < 0)
350 printf("Wrong prf file\n");
354 if (init_buffer() < 0)
356 printf("Malloc error\n");
361 if (WSAStartup(wVersionRequested, &wsaData))
363 msg_print("Report: WSAStartup failed.");
368 printf("server = %s\nport = %d\n", server_name, server_port);
370 if ((hp = gethostbyname(server_name)) != NULL)
372 memset(&ask, 0, sizeof(ask));
373 memcpy(&ask.sin_addr, hp->h_addr_list[0], hp->h_length);
377 if ((ask.sin_addr.s_addr=inet_addr(server_name)) == 0)
379 printf("Bad hostname\n");
384 ask.sin_family = AF_INET;
385 ask.sin_port = htons((unsigned short)server_port);
388 if ((sd=socket(PF_INET,SOCK_STREAM, 0)) < 0)
390 if ((sd=socket(PF_INET,SOCK_STREAM, 0)) == INVALID_SOCKET)
393 printf("Can't create socket\n");
397 if (connect(sd, (struct sockaddr *)&ask, sizeof(ask)) < 0)
400 printf("Can't connect %s port %d\n", server_name, server_port);
405 #else /* MACINTOSH */
407 InetHostInfo response;
411 Boolean bind = false;
414 if (read_chuukei_prf(prf_name) < 0){
415 printf("Wrong prf file\n");
421 printf("server = %s\nport = %d\n", server_name, server_port);
424 #if TARGET_API_MAC_CARBON
425 err = InitOpenTransportInContext(kInitOTForApplicationMask, NULL);
427 err = InitOpenTransport();
430 memset(&response, 0, sizeof(response));
433 #if TARGET_API_MAC_CARBON
434 inet_services = OTOpenInternetServicesInContext(kDefaultInternetServicesPath, 0, &err, NULL);
436 inet_services = OTOpenInternetServices(kDefaultInternetServicesPath, 0, &err);
440 err = OTInetStringToAddress(inet_services, (char *)server_name, &response);
443 host_addr = response.addrs[0];
445 printf("Bad hostname\n");
448 #if TARGET_API_MAC_CARBON
449 ep = (void *)OTOpenEndpointInContext(OTCreateConfiguration(kTCPName), 0, nil, &err, NULL);
451 ep = (void *)OTOpenEndpoint(OTCreateConfiguration(kTCPName), 0, nil, &err);
455 err = OTBind(ep, nil, nil);
456 bind = (err == noErr);
459 OTInitInetAddress(&inAddr, server_port, host_addr);
461 sndCall.addr.len = sizeof(InetAddress);
462 sndCall.addr.buf = (unsigned char*) &inAddr;
463 sndCall.opt.buf = nil; /* no connection options */
465 sndCall.udata.buf = nil; /* no connection data */
466 sndCall.udata.len = 0;
467 sndCall.sequence = 0; /* ignored by OTConnect */
469 err = OTConnect(ep, &sndCall, NULL);
472 printf("Can't connect %s port %d\n", server_name, server_port);
476 err = OTSetSynchronous(ep);
478 err = OTSetBlocking(ep);
487 if (ep != kOTInvalidEndpointRef) {
491 if (inet_services != nil) {
492 OTCloseProvider(inet_services);
505 /* strが同じ文字の繰り返しかどうか調べる */
506 static bool string_is_repeat(char *str, int len)
511 if (len < 2) return (FALSE);
513 if (iskanji(c)) return (FALSE);
516 for (i = 1; i < len; i++)
519 if(c != str[i] || iskanji(str[i])) return (FALSE);
521 if(c != str[i]) return (FALSE);
528 static errr send_text_to_chuukei_server(TERM_LEN x, TERM_LEN y, int len, TERM_COLOR col, concptr str)
533 strncpy(buf2, str, len);
538 sprintf(buf, "s%c%c%c%c", x+1, y+1, col, buf2[0]);
540 else if(string_is_repeat(buf2, len))
543 for (i = len; i > 0; i -= 127)
545 sprintf(buf, "n%c%c%c%c%c", x+1, y+1, MIN(i, 127), col, buf2[0]);
550 #if defined(SJIS) && defined(JP)
553 sprintf(buf, "t%c%c%c%c%s", x+1, y+1, len, col, buf2);
558 return (*old_text_hook)(x, y, len, col, str);
561 static errr send_wipe_to_chuukei_server(int x, int y, int len)
565 sprintf(buf, "w%c%c%c", x+1, y+1, len);
569 return (*old_wipe_hook)(x, y, len);
572 static errr send_xtra_to_chuukei_server(int n, int v)
576 if (n == TERM_XTRA_CLEAR || n == TERM_XTRA_FRESH || n == TERM_XTRA_SHAPE)
578 sprintf(buf, "x%c", n+1);
582 if (n == TERM_XTRA_FRESH)
584 sprintf(buf, "d%ld", get_current_time() - epoch_time);
589 /* Verify the hook */
590 if (!old_xtra_hook) return -1;
592 return (*old_xtra_hook)(n, v);
595 static errr send_curs_to_chuukei_server(int x, int y)
599 sprintf(buf, "c%c%c", x+1, y+1);
603 return (*old_curs_hook)(x, y);
606 static errr send_bigcurs_to_chuukei_server(int x, int y)
610 sprintf(buf, "C%c%c", x+1, y+1);
614 return (*old_bigcurs_hook)(x, y);
619 * Prepare z-term hooks to call send_*_to_chuukei_server()'s
621 void prepare_chuukei_hooks(void)
623 term *t0 = angband_term[0];
625 /* Save original z-term hooks */
626 old_xtra_hook = t0->xtra_hook;
627 old_curs_hook = t0->curs_hook;
628 old_bigcurs_hook = t0->bigcurs_hook;
629 old_wipe_hook = t0->wipe_hook;
630 old_text_hook = t0->text_hook;
632 /* Prepare z-term hooks */
633 t0->xtra_hook = send_xtra_to_chuukei_server;
634 t0->curs_hook = send_curs_to_chuukei_server;
635 t0->bigcurs_hook = send_bigcurs_to_chuukei_server;
636 t0->wipe_hook = send_wipe_to_chuukei_server;
637 t0->text_hook = send_text_to_chuukei_server;
642 * Prepare z-term hooks to call send_*_to_chuukei_server()'s
644 void prepare_movie_hooks(void)
653 if (!chuukei_server) disable_chuukei_server();
655 disable_chuukei_server();
658 msg_print(_("録画を終了しました。", "Stopped recording."));
662 sprintf(tmp, "%s.amv", player_base);
663 if (get_string(_("ムービー記録ファイル: ", "Movie file name: "), tmp, 80))
667 path_build(buf, sizeof(buf), ANGBAND_DIR_USER, tmp);
669 fd = fd_open(buf, O_RDONLY);
678 (void)sprintf(out_val, _("現存するファイルに上書きしますか? (%s)", "Replace existing file %s? "), buf);
681 if (!get_check(out_val)) return;
683 movie_fd = fd_open(buf, O_WRONLY | O_TRUNC);
687 movie_fd = fd_make(buf, 0644);
692 msg_print(_("ファイルを開けません!", "Can not open file."));
698 if (!chuukei_server) prepare_chuukei_hooks();
700 prepare_chuukei_hooks();
708 static int handle_timestamp_data(int timestamp)
710 long current_time = get_current_time();
713 if (fresh_queue.tail == fresh_queue.next)
715 /* バッファリングし始めの時間を保存しておく */
716 epoch_time = current_time;
717 epoch_time += browse_delay;
718 epoch_time -= timestamp;
719 time_diff = current_time - timestamp;
722 /* 描画キューに保存し、保存位置を進める */
723 fresh_queue.time[fresh_queue.tail] = timestamp;
726 /* キューの最後尾に到達したら先頭に戻す */
727 fresh_queue.tail %= FRESH_QUEUE_SIZE;
729 if (fresh_queue.tail == fresh_queue.next)
732 prt("描画タイミングキューが溢れました。サーバとの接続を切断します。", 0, 0);
740 if (time_diff != current_time - timestamp)
742 long old_time_diff = time_diff;
743 time_diff = current_time - timestamp;
744 epoch_time -= (old_time_diff - time_diff);
752 static int handle_movie_timestamp_data(int timestamp)
754 static int initialized = FALSE;
759 /* バッファリングし始めの時間を保存しておく */
760 epoch_time = get_current_time();
761 epoch_time += browse_delay;
762 epoch_time -= timestamp;
763 //time_diff = current_time - timestamp;
767 /* 描画キューに保存し、保存位置を進める */
768 fresh_queue.time[fresh_queue.tail] = timestamp;
771 /* キューの最後尾に到達したら先頭に戻す */
772 fresh_queue.tail %= FRESH_QUEUE_SIZE;
779 static int read_sock(void)
781 static char recv_buf[RECVBUF_SIZE];
782 static int remain_bytes = 0;
786 /* 前回残ったデータの後につづけて配信サーバからデータ受信 */
787 recv_bytes = recv(sd, recv_buf + remain_bytes, RECVBUF_SIZE - remain_bytes, 0);
792 /* 前回残ったデータ量に今回読んだデータ量を追加 */
793 remain_bytes += recv_bytes;
795 for (i = 0; i < remain_bytes; i ++)
797 /* データのくぎり('\0')を探す */
798 if (recv_buf[i] == '\0')
800 /* 'd'で始まるデータ(タイムスタンプ)の場合は
802 if ((recv_buf[0] == 'd') &&
803 (handle_timestamp_data(atoi(recv_buf + 1)) < 0))
807 if (insert_ringbuf(recv_buf) < 0)
810 /* 次のデータ移行をrecv_bufの先頭に移動 */
811 memmove(recv_buf, recv_buf + i + 1, remain_bytes - i - 1);
813 remain_bytes -= (i+1);
822 static int read_movie_file(void)
824 static char recv_buf[RECVBUF_SIZE];
825 static int remain_bytes = 0;
829 recv_bytes = read(movie_fd, recv_buf + remain_bytes, RECVBUF_SIZE - remain_bytes);
834 /* 前回残ったデータ量に今回読んだデータ量を追加 */
835 remain_bytes += recv_bytes;
837 for (i = 0; i < remain_bytes; i ++)
839 /* データのくぎり('\0')を探す */
840 if (recv_buf[i] == '\0')
842 /* 'd'で始まるデータ(タイムスタンプ)の場合は
844 if ((recv_buf[0] == 'd') &&
845 (handle_movie_timestamp_data(atoi(recv_buf + 1)) < 0))
849 if (insert_ringbuf(recv_buf) < 0)
852 /* 次のデータ移行をrecv_bufの先頭に移動 */
853 memmove(recv_buf, recv_buf + i + 1, remain_bytes - i - 1);
855 remain_bytes -= (i+1);
865 /* Win版の床の中点と壁の豆腐をピリオドとシャープにする。*/
866 static void win2unix(int col, char *buf)
869 if ( col == 9 ) kabe = '%';
881 if (*buf == 127) *buf = kabe;
882 else if(*buf == 31) *buf = '.';
888 static bool get_nextbuf(char *buf)
894 *ptr = ring.buf[ring.rptr ++];
896 if (ring.rptr == RINGBUF_SIZE) ring.rptr = 0;
897 if (*ptr++ == '\0') break;
900 if (buf[0] == 'd') return (FALSE);
905 /* プレイホストのマップが大きいときクライアントのマップもリサイズする */
906 static void update_term_size(int x, int y, int len)
910 Term_get_size(&ox, &oy);
915 if (x + len > ox) nx = x + len;
917 if (y + 1 > oy) ny = y + 1;
919 if (nx != ox || ny != oy) Term_resize(nx, ny);
922 static bool flush_ringbuf_client(void)
927 if (fresh_queue.next == fresh_queue.tail) return (FALSE);
930 if (fresh_queue.time[fresh_queue.next] > get_current_time() - epoch_time) return (FALSE);
932 /* 時間情報(区切り)が得られるまで書く */
933 while (get_nextbuf(buf))
939 unsigned char tmp1, tmp2, tmp3, tmp4;
942 sscanf(buf, "%c%c%c%c%c", &id, &tmp1, &tmp2, &tmp3, &tmp4);
943 x = tmp1-1; y = tmp2-1; len = tmp3; col = tmp4;
957 #if defined(SJIS) && defined(JP)
960 update_term_size(x, y, len);
961 (void)((*angband_term[0]->text_hook)(x, y, len, (byte)col, mesg));
962 strncpy(&Term->scr->c[y][x], mesg, len);
963 for (i = x; i < x+len; i++)
965 Term->scr->a[y][i] = col;
970 for (i = 1; i < len; i++)
975 update_term_size(x, y, len);
976 (void)((*angband_term[0]->text_hook)(x, y, len, (byte)col, mesg));
977 strncpy(&Term->scr->c[y][x], mesg, len);
978 for (i = x; i < x+len; i++)
980 Term->scr->a[y][i] = col;
985 update_term_size(x, y, 1);
986 (void)((*angband_term[0]->text_hook)(x, y, 1, (byte)col, mesg));
987 strncpy(&Term->scr->c[y][x], mesg, 1);
988 Term->scr->a[y][x] = col;
992 update_term_size(x, y, len);
993 (void)((*angband_term[0]->wipe_hook)(x, y, len));
997 if (x == TERM_XTRA_CLEAR) Term_clear();
998 (void)((*angband_term[0]->xtra_hook)(x, 0));
1002 update_term_size(x, y, 1);
1003 (void)((*angband_term[0]->curs_hook)(x, y));
1006 update_term_size(x, y, 1);
1007 (void)((*angband_term[0]->bigcurs_hook)(x, y));
1013 if (fresh_queue.next == FRESH_QUEUE_SIZE) fresh_queue.next = 0;
1018 void browse_chuukei()
1032 Term_xtra(TERM_XTRA_REACT, 0);
1037 struct timeval tmp_tv;
1039 if (flush_ringbuf_client()) continue;
1044 /* ソケットにデータが来ているかどうか調べる */
1045 select(sd+1, &tmp_fdset, (fd_set *)NULL, (fd_set *)NULL, &tmp_tv);
1046 if (FD_ISSET(sd, &tmp_fdset) == 0)
1048 Term_xtra(TERM_XTRA_FLUSH, 0);
1052 if (read_sock() < 0)
1054 chuukei_client = FALSE;
1057 /* 接続が切れた状態で書くべきデータがなくなっていたら終了 */
1058 if (!chuukei_client && fresh_queue.next == fresh_queue.tail ) break;
1063 Term_xtra(TERM_XTRA_REACT, 0);
1067 UInt32 unreadData = 0;
1070 if (flush_ringbuf_client()) continue;
1072 /* ソケットにデータが来ているかどうか調べる */
1074 OTCountDataBytes(ep, &unreadData);
1075 if(unreadData <= 0 ){
1076 Term_xtra(TERM_XTRA_FLUSH, 0);
1079 if (read_sock() < 0)
1081 chuukei_client = FALSE;
1084 /* 接続が切れた状態で書くべきデータがなくなっていたら終了 */
1085 if (!chuukei_client && fresh_queue.next == fresh_queue.tail ) break;
1087 #endif /*MACINTOSH*/
1089 #endif /* CHUUKEI */
1091 void prepare_browse_movie_aux(concptr filename)
1093 movie_fd = fd_open(filename, O_RDONLY);
1095 browsing_movie = TRUE;
1100 void prepare_browse_movie(concptr filename)
1103 path_build(buf, sizeof(buf), ANGBAND_DIR_USER, filename);
1105 prepare_browse_movie_aux(buf);
1108 void browse_movie(void)
1112 Term_xtra(TERM_XTRA_REACT, 0);
1114 while (read_movie_file() == 0)
1116 while (fresh_queue.next != fresh_queue.tail)
1118 if (!flush_ringbuf_client())
1120 Term_xtra(TERM_XTRA_FLUSH, 0);
1122 /* ソケットにデータが来ているかどうか調べる */