]> git.tdb.fi Git - r2c2.git/blob - source/network/server.cpp
Export AI control parameters over the network
[r2c2.git] / source / network / server.cpp
1 #include <msp/core/refptr.h>
2 #include <msp/net/inet.h>
3 #include <msp/net/resolve.h>
4 #include "libr2c2/aicontrol.h"
5 #include "libr2c2/catalogue.h"
6 #include "libr2c2/driver.h"
7 #include "libr2c2/route.h"
8 #include "libr2c2/train.h"
9 #include "libr2c2/trainrouter.h"
10 #include "libr2c2/trainstatus.h"
11 #include "libr2c2/vehicletype.h"
12 #include "server.h"
13
14 using namespace std;
15 using namespace Msp;
16
17 namespace R2C2 {
18
19 Server::Server(Layout &l):
20         layout(l),
21         listen_sock(Net::INET),
22         event_disp(0)
23 {
24         layout.get_driver().signal_power.connect(sigc::hide(sigc::mem_fun(this, &Server::driver_state_changed)));
25         layout.get_driver().signal_halt.connect(sigc::hide(sigc::mem_fun(this, &Server::driver_state_changed)));
26         layout.signal_emergency.connect(sigc::mem_fun(this, &Server::emergency));
27
28         layout.signal_train_added.connect(sigc::mem_fun(this, &Server::train_added));
29
30         const map<unsigned, Train *> &trains = layout.get_trains();
31         for(map<unsigned, Train *>::const_iterator i=trains.begin(); i!=trains.end(); ++i)
32                 train_added(*i->second);
33
34         RefPtr<Net::SockAddr> addr = Net::resolve("*", "8315", Net::INET);
35         listen_sock.listen(*addr, 4);
36         listen_sock.signal_data_available.connect(sigc::mem_fun(this, &Server::incoming_connection));
37 }
38
39 Server::~Server()
40 { }
41
42 void Server::use_event_dispatcher(IO::EventDispatcher &ed)
43 {
44         event_disp = &ed;
45         event_disp->add(listen_sock);
46 }
47
48 void Server::incoming_connection()
49 {
50         Net::StreamSocket *sock = listen_sock.accept();
51         if(event_disp)
52                 event_disp->add(*sock);
53         connections.push_back(new Connection(*this, sock));
54 }
55
56 void Server::driver_state_changed()
57 {
58         DriverStatePacket pkt;
59         pkt.power = layout.get_driver().get_power();
60         pkt.halt = layout.get_driver().is_halted();
61         send(pkt);
62 }
63
64 void Server::emergency(Block *, const string &msg)
65 {
66         EmergencyPacket pkt;
67         pkt.message = msg;
68         send(pkt);
69 }
70
71 void Server::train_added(Train &train)
72 {
73         train.signal_control_changed.connect(sigc::bind<0>(sigc::mem_fun(this, &Server::train_control_changed), sigc::ref(train)));
74         train.signal_function_changed.connect(sigc::bind<0>(sigc::mem_fun(this, &Server::train_function_changed), sigc::ref(train)));
75         train.signal_ai_event.connect(sigc::bind<0>(sigc::mem_fun(this, &Server::train_ai_event), sigc::ref(train)));
76
77         TrainInfoPacket pkt;
78         pkt.address = train.get_address();
79         pkt.loco_type = layout.get_catalogue().get_name(&train.get_locomotive_type());
80         pkt.name = train.get_name();
81         send(pkt);
82
83         if(!train.get_ai_of_type<TrainStatus>())
84                 new TrainStatus(train);
85 }
86
87 void Server::train_control_changed(const Train &train, const string &control, float value)
88 {
89         TrainControlPacket pkt;
90         pkt.address = train.get_address();
91         pkt.control = control;
92         pkt.value = value;
93         send(pkt);
94 }
95
96 void Server::train_function_changed(const Train &train, unsigned, bool)
97 {
98         TrainFunctionPacket pkt;
99         pkt.address = train.get_address();
100         pkt.functions = train.get_functions();
101         send(pkt);
102 }
103
104 void Server::train_ai_event(const Train &train, TrainAI &ai, const TrainAI::Message &ev)
105 {
106         if(ev.type=="route-changed")
107         {
108                 TrainRoutePacket pkt;
109                 pkt.address = train.get_address();
110                 if(const Route *route = ev.value.value<const Route *>())
111                         pkt.route = route->get_name();
112                 send(pkt);
113         }
114         else if(ev.type=="status-changed")
115         {
116                 TrainStatusPacket pkt;
117                 pkt.address = train.get_address();
118                 pkt.status = ev.value.value<std::string>();
119                 send(pkt);
120         }
121         else if(ev.type=="target-speed-changed" || ev.type=="reverse-changed")
122         {
123                 AIControl *control = dynamic_cast<AIControl *>(&ai);
124                 if(control)
125                 {
126                         TrainAIControlPacket pkt;
127                         pkt.address = train.get_address();
128                         pkt.target_speed = control->get_target_speed();
129                         pkt.reverse = control->get_reverse();
130                         send(pkt);
131                 }
132         }
133 }
134
135 template<typename P>
136 void Server::send(const P &pkt)
137 {
138         for(vector<Connection *>::const_iterator i=connections.begin(); i!=connections.end(); ++i)
139                 if(!(*i)->stale && (*i)->comm.is_handshake_done())
140                         (*i)->comm.send(pkt);
141 }
142
143
144 Server::Connection::Connection(Server &s, Net::StreamSocket *o):
145         server(s),
146         socket(o),
147         comm(*socket, server.proto, *this)
148 {
149         socket->signal_end_of_file.connect(sigc::mem_fun(this, &Connection::end_of_file));
150         comm.signal_handshake_done.connect(sigc::mem_fun(this, &Connection::handshake_done));
151         comm.signal_error.connect(sigc::mem_fun(this, &Connection::comm_error));
152         comm.initiate_handshake();
153 }
154
155 Server::Connection::~Connection()
156 {
157         delete socket;
158 }
159
160 void Server::Connection::handshake_done()
161 {
162         {
163                 DriverStatePacket pkt;
164                 pkt.power = server.layout.get_driver().get_power();
165                 pkt.halt = server.layout.get_driver().is_halted();
166                 comm.send(pkt);
167         }
168
169         const set<Route *> &routes = server.layout.get_all<Route>();
170         for(set<Route *>::const_iterator i=routes.begin(); i!=routes.end(); ++i)
171                 if(!(*i)->is_temporary())
172                 {
173                         RouteInfoPacket pkt;
174                         pkt.name = (*i)->get_name();
175                         comm.send(pkt);
176                 }
177
178         const Catalogue &cat = server.layout.get_catalogue();
179         const map<unsigned, Train *> &trains = server.layout.get_trains();
180         for(map<unsigned, Train *>::const_iterator i=trains.begin(); i!=trains.end(); ++i)
181         {
182                 const Train &train = *i->second;
183
184                 {
185                         TrainInfoPacket pkt;
186                         pkt.address = train.get_address();
187                         pkt.loco_type = cat.get_name(&train.get_locomotive_type());
188                         pkt.name = train.get_name();
189                         comm.send(pkt);
190                 }
191                 if(AIControl *control = train.get_ai_of_type<AIControl>())
192                 {
193                         TrainAIControlPacket pkt;
194                         pkt.address = train.get_address();
195                         pkt.target_speed = control->get_target_speed();
196                         pkt.reverse = control->get_reverse();
197                         comm.send(pkt);
198                 }
199                 for(unsigned j=0;; ++j)
200                 {
201                         const char *name = train.get_controller().enumerate_controls(j);
202                         if(!name)
203                                 break;
204
205                         TrainControlPacket pkt;
206                         pkt.address = train.get_address();
207                         pkt.control = name;
208                         pkt.value = train.get_control(name);
209                         comm.send(pkt);
210                 }
211                 {
212                         TrainFunctionPacket pkt;
213                         pkt.address = train.get_address();
214                         pkt.functions = train.get_functions();
215                         comm.send(pkt);
216                 }
217                 if(TrainStatus *status = train.get_ai_of_type<TrainStatus>())
218                 {
219                         TrainStatusPacket pkt;
220                         pkt.address = train.get_address();
221                         pkt.status = status->get_status();
222                         comm.send(pkt);
223                 }
224                 if(TrainRouter *router = train.get_ai_of_type<TrainRouter>())
225                 {
226                         TrainRoutePacket pkt;
227                         pkt.address = train.get_address();
228                         pkt.route = router->get_route()->get_name();
229                         comm.send(pkt);
230                 }
231         }
232 }
233
234 void Server::Connection::end_of_file()
235 {
236         stale = true;
237 }
238
239 void Server::Connection::receive(const DriverStatePacket &pkt)
240 {
241         Driver &driver = server.layout.get_driver();
242         if(pkt.power!=driver.get_power())
243                 driver.set_power(pkt.power);
244         if(pkt.halt!=driver.is_halted())
245                 driver.halt(pkt.halt);
246 }
247
248 void Server::Connection::receive(const TrainControlPacket &pkt)
249 {
250         try
251         {
252                 Train &train = server.layout.get_train(pkt.address);
253                 train.set_control(pkt.control, pkt.value);
254         }
255         catch(const exception &e)
256         {
257                 error(e.what());
258         }
259 }
260
261 void Server::Connection::receive(const TrainFunctionPacket &pkt)
262 {
263         try
264         {
265                 Train &train = server.layout.get_train(pkt.address);
266                 for(unsigned i=0; i<9; ++i)
267                         if(((pkt.functions^train.get_functions())>>i)&1)
268                                 train.set_function(i, (pkt.functions>>i)&1);
269         }
270         catch(const exception &e)
271         {
272                 error(e.what());
273         }
274 }
275
276 void Server::Connection::receive(const TrainAIControlPacket &pkt)
277 {
278         try
279         {
280                 Train &train = server.layout.get_train(pkt.address);
281                 train.ai_message(TrainAI::Message("set-target-speed", pkt.target_speed));
282                 train.ai_message(TrainAI::Message("set-reverse", pkt.reverse));
283         }
284         catch(const exception &e)
285         {
286                 error(e.what());
287         }
288 }
289
290 void Server::Connection::receive(const TrainRoutePacket &pkt)
291 {
292         try
293         {
294                 Train &train = server.layout.get_train(pkt.address);
295                 if(pkt.route.empty())
296                         train.ai_message(TrainAI::Message("clear-route"));
297                 else
298                 {
299                         Route &route = server.layout.get_route(pkt.route);
300                         train.ai_message(TrainAI::Message("set-route", &route));
301                 }
302         }
303         catch(const exception &e)
304         {
305                 error(e.what());
306         }
307 }
308
309 void Server::Connection::comm_error(const exception &)
310 {
311         stale = true;
312 }
313
314 void Server::Connection::error(const string &msg)
315 {
316         ErrorPacket pkt;
317         pkt.message = msg;
318         comm.send(pkt);
319 }
320
321 } // namespace R2C2