19
20:- dynamic(adv:wants_quit/3). 21:- dynamic(adv:console_tokens/2). 22
23:- dynamic(adv:console_io_conn_history/7). 24:- dynamic(adv:console_io_player/3). 25:- volatile(adv:console_io_player/3). 26:- volatile(adv:console_io_conn_history/7). 27
28:- use_module(library(socket)). 29
30adv_server(Port) :-
31 bugout1(adv_server(Port)),
32 tcp_socket(ServerSocket),
33 tcp_setopt(ServerSocket, reuseaddr),
34 tcp_bind(ServerSocket, Port),
35 tcp_listen(ServerSocket, 5),
36 atom_concat('mu_', Port, Alias),
37 thread_create(adv_server_loop(Port, ServerSocket), _,
38 [ alias(Alias)
39 ]).
40
41peer_alias(Prefix,Peer, Host, Alias):-
42 (tcp_host_to_address(Host, Peer);Host=Peer),
43 format(string(S),'~w@~w_',[Host,Prefix]),
44 gensym(S,Alias),!.
45
46adv_server_loop(Prefix, ServerSocket) :-
47 tcp_accept(ServerSocket, Slave, Peer),
48 tcp_open_socket(Slave, InStream, OutStream),
49 50 set_stream(InStream, close_on_exec(true)),
51 set_stream(OutStream, close_on_exec(true)),
52 set_stream(InStream, close_on_abort(true)),
53 set_stream(OutStream, close_on_abort(true)),
54 peer_alias(Prefix, Peer, Host, Alias),
55 ignore(catch(thread_create(
56 adv_serve_client(InStream, OutStream, Host, Peer, Alias),
57 _,
58 [ alias(Alias)
59 ]),
60 error(permission_error(create, thread, Alias), _),
61 fail)),
62 !,
63 adv_server_loop(Prefix, ServerSocket).
64
65setup_IO_props(InStream, OutStream):-
66 set_stream(InStream, tty(true)),
67 set_stream(OutStream, tty(true)),
68 69 70 current_prolog_flag(encoding, Enc),
71 set_stream(user_input, encoding(Enc)),
72 73 set_stream(user_output, encoding(Enc)),
74 75 set_stream(user_input, newline(detect)),
76 set_stream(user_output, newline(dos)),
77 set_stream(user_input, eof_action(eof_code)),!.
78
79adv_serve_client(InStream, OutStream, Host, Peer, Alias) :-
80 !,
81 thread_self(Id),
82
83 set_prolog_IO(InStream, OutStream, OutStream),
84 85 set_stream(OutStream, alias(user_error)),
86 set_stream(OutStream, alias(user_output)),
87
88 setup_IO_props(InStream, OutStream),
89
90 set_stream(user_input, close_on_exec(false)),
91 set_stream(user_input, close_on_abort(false)),
92 set_stream(user_output, close_on_exec(false)),
93 set_stream(user_output, close_on_abort(false)),
94
95 format(OutStream,
96 'Welcome to the SWI-Prolog Adventure Server!~n~q~n~n',
97 [adv_serve_client(Id,Alias,InStream,OutStream, Host, Peer)]), !,
98 call_cleanup(srv_catch(adventure_client_process(Id,Alias,InStream,OutStream, Host, Peer)),
99 adventure_client_cleanp(Id,Alias,InStream,OutStream)).
100
101srv_catch(Goal):- catch(once(call(call,Goal)),E,((notrace(bugout1(error_srv_catch(E,Goal))),!,fail))).
102ignore_srv_catch(Goal):- ignore(srv_catch(Goal)).
103tflush(OutStream):- ignore_srv_catch((flush_output(OutStream), ttyflush)).
104
105adventure_client_cleanp(Id,Alias,InStream,OutStream):-
106 ignore(notice_agent_discon(Id,Alias,InStream,OutStream)),
107 retractall(adv:console_io_player(_,OutStream,_)),
108 retractall(adv:console_io_player(InStream,_,_)),
109 ignore_srv_catch(close(InStream)),
110 ignore_srv_catch(close(OutStream)),
111 ignore_srv_catch(thread_detach(Id)).
112
113notice_agent_discon(Id,Alias,InStream,OutStream):-
114 once((
115 adv:console_io_player(InStream,_,Agent);
116 adv:console_io_player(_,OutStream,Agent);
117 (adv:console_io_conn_history(_, Alias,_,_, _, _, Agent), \+ adv:console_io_player(_,_,Agent));
118 (adv:console_io_conn_history(Id, _,_,_, _, _, Agent), \+ adv:console_io_player(_,_,Agent)))),
119 assertz(adv:agent_discon(Agent)),
120 bugout1((adv:agent_discon(Agent))),!.
121
122
123:- dynamic(adv:peer_character/2). 124:- dynamic(adv:peer_agent/2). 125:- dynamic(adv:agent_character/2). 126:- dynamic(adv:agent_discon/1). 127
128guess_previous_agent_0(_, Peer, Agent):- adv:peer_agent(Peer, Agent),!.
129guess_previous_agent_0(Host, _, Agent):- adv:peer_agent(Host, Agent),!.
130
131guess_previous_agent(Host, Peer, Agent):- guess_previous_agent_0(Host, Peer, Agent),
132 \+ adv:console_io_player(_, _, Agent).
133
134guess_previous_agent(_Host, _Peer, Agent):- gensym('telnet~',Agent).
135
136prompt_for_agent(Id,Alias,InStream,OutStream, Host, Peer, Agent,Name):-
137 guess_previous_agent(Host, Peer, Agent),
138 ignore(adv:agent_character(Agent,Name)),
139 ignore(adv:peer_character(Peer,Name)),
140 ignore(adv:peer_character(Host,Name)),
141 (var(Name) -> format(OutStream, 'Enter your name [or leave bank for "~w"]: ', [Agent]), read_line_to_string(InStream,Name) ; true),
142 accept_agent(Id,Alias,InStream,OutStream, Host, Peer, Agent,Name).
143
144aaifn(A):- clause(A,true)->true;asserta(A).
145
146accept_agent(Id,Alias,InStream,OutStream, Host, Peer, Agent,Name):-
147 aaifn(adv:agent_character(Agent,Name)),
148 aaifn(adv:peer_character(Peer,Name)),
149 aaifn(adv:peer_character(Host,Name)),
150 aaifn(adv:peer_agent(Peer,Agent)),
151 aaifn(adv:peer_agent(Host,Agent)),
152 153 asserta(adv:console_io_conn_history(Id,Alias,InStream,OutStream, Host, Peer, Agent)),
154 retractall(adv:console_io_player(InStream,_,_)),
155 retractall(adv:console_io_player(_,OutStream,_)),
156 retractall(adv:console_io_player(_,_,Agent)),
157 asserta(adv:console_io_player(InStream,OutStream,Agent)),
158 assertz(adv:agent_conn(Agent,Name,Alias,adventure_client_process(Id,Alias,InStream,OutStream, Host, Peer))),!.
159
160welcome_adv_tnet(OutStream):-
161 format(OutStream, '==============================================~n', []),
162 format(OutStream, 'Welcome to Marty\'s Prolog Adventure Prototype~n', []),
163 format(OutStream, '==============================================~n', []),
164 !.
165
166adventure_client_process(Id,Alias,InStream,OutStream, Host, Peer):-
167 prompt_for_agent(Id,Alias,InStream,OutStream, Host, Peer, Agent,_Name),
168 retractall(adv:wants_quit(_,InStream,_)),
169 retractall(adv:wants_quit(Id,_,_)),
170 welcome_adv_tnet(OutStream),
171 overwrote_prompt(Agent),
172 setup_console,
173 repeat,
174 must(adv:console_io_player(InStream, OutStream, CurrentAgent)),
175 adv_tlnet_readloop(Id, InStream, OutStream, CurrentAgent),
176 needs_logout_p(Id, InStream, CurrentAgent), !.
177
178needs_logout_p(Id, InStream, _Agent):-
179 adv:wants_quit(Id, _, _);
180 adv:wants_quit(_, InStream, _).
181needs_logout_p(_, InStream, _Agent):-
182 \+ adv:console_io_player(InStream, _, _).
183needs_logout_p(_, InStream, Agent):-
184 adv:wants_quit(_, _, Agent),
185 \+ (( adv:console_io_player(InStream, _, Other), Other\==Agent)).
186
187adv_tlnet_readloop(Id, InStream, _OutStream, Agent):-
188 needs_logout_p(Id, InStream, Agent),
189 sleep(0.1), !.
190adv_tlnet_readloop(_Id, _InStream, OutStream, Agent):-
191 adv:console_tokens(Agent, _Words),
192 tflush(OutStream),
193 sleep(0.1), !.
194adv_tlnet_readloop(_Id, InStream, OutStream, Agent):-
195 ensure_has_prompt(Agent),
196 current_input(In), wait_for_input([In,InStream,user_input],Found,0.1),
197 Found==[], !,
198 tflush(OutStream).
199adv_tlnet_readloop(Id, InStream, OutStream, Agent):-
200 read_line_to_tokens(Agent,InStream,[],Words),
201 tflush(OutStream),
202 must_det(adv_tlnet_words(Id, InStream, Agent, Words)),!.
203
204
205adv_tlnet_words(Id, InStream, Agent, []):-
206 adv_tlnet_words( Id, InStream, Agent, [wait]).
207adv_tlnet_words(Id, InStream, Agent, [quit]):-
208 adv_tlnet_words(Id, InStream, Agent, end_of_file).
209adv_tlnet_words(Id, InStream, Agent, end_of_file):-
210 asserta(adv:wants_quit(Id, InStream, Agent)),
211 bugout3('~NTelent: ~q~n', [adv:wants_quit(Id, InStream, Agent)], telnet).
212adv_tlnet_words(_Id, _InStream, _Agent, [prolog]):- !,
213 prolog.
214adv_tlnet_words(Id, InStream, Agent, Words):-
215 assertz(adv:console_tokens(Agent, Words)),
216 nop((bugout3('~NTelent: ~q~n', [adv_tlnet_words(Id, InStream, Agent, Words)], telnet))),
217 218 !