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