|
1 #include "mapconn.h" |
|
2 #include "ipcconn.h" |
|
3 #include "ipcprotocol.h" |
|
4 |
|
5 #include "../logging.h" |
|
6 #include "../buffer.h" |
|
7 |
|
8 #include <stdlib.h> |
|
9 |
|
10 typedef enum { |
|
11 AWAIT_CONNECTION, |
|
12 AWAIT_REPLY, |
|
13 FINISHED |
|
14 } mapconn_progress; |
|
15 |
|
16 struct _flib_mapconn { |
|
17 uint8_t mapBuffer[IPCCONN_MAPMSG_BYTES]; |
|
18 flib_ipcconn connection; |
|
19 flib_vector configBuffer; |
|
20 |
|
21 mapconn_progress progress; |
|
22 |
|
23 void (*onSuccessCb)(void*, const uint8_t*, int); |
|
24 void *onSuccessCtx; |
|
25 |
|
26 void (*onFailureCb)(void*, const char*); |
|
27 void *onFailureCtx; |
|
28 |
|
29 bool running; |
|
30 bool destroyRequested; |
|
31 }; |
|
32 |
|
33 static void noop_handleSuccess(void *context, const uint8_t *bitmap, int numHedgehogs) {} |
|
34 static void noop_handleFailure(void *context, const char *errormessage) {} |
|
35 |
|
36 static void clearCallbacks(flib_mapconn *conn) { |
|
37 conn->onSuccessCb = &noop_handleSuccess; |
|
38 conn->onFailureCb = &noop_handleFailure; |
|
39 } |
|
40 |
|
41 static flib_vector createConfigBuffer(char *seed, flib_map *mapdesc) { |
|
42 flib_vector result = NULL; |
|
43 flib_vector tempbuffer = flib_vector_create(); |
|
44 if(tempbuffer) { |
|
45 bool error = false; |
|
46 error |= flib_ipc_append_seed(tempbuffer, seed); |
|
47 error |= flib_ipc_append_mapconf(tempbuffer, mapdesc, true); |
|
48 error |= flib_ipc_append_message(tempbuffer, "!"); |
|
49 if(!error) { |
|
50 result = tempbuffer; |
|
51 tempbuffer = NULL; |
|
52 } |
|
53 } |
|
54 flib_vector_destroy(&tempbuffer); |
|
55 return result; |
|
56 } |
|
57 |
|
58 flib_mapconn *flib_mapconn_create(char *seed, flib_map *mapdesc) { |
|
59 flib_mapconn *result = NULL; |
|
60 flib_mapconn *tempConn = calloc(1, sizeof(flib_mapconn)); |
|
61 if(tempConn) { |
|
62 tempConn->connection = flib_ipcconn_create(false, "Player"); |
|
63 tempConn->configBuffer = createConfigBuffer(seed, mapdesc); |
|
64 if(tempConn->connection && tempConn->configBuffer) { |
|
65 tempConn->progress = AWAIT_CONNECTION; |
|
66 clearCallbacks(tempConn); |
|
67 result = tempConn; |
|
68 tempConn = NULL; |
|
69 } |
|
70 } |
|
71 flib_mapconn_destroy(tempConn); |
|
72 return result; |
|
73 } |
|
74 |
|
75 void flib_mapconn_destroy(flib_mapconn *conn) { |
|
76 if(conn) { |
|
77 if(conn->running) { |
|
78 /* |
|
79 * The function was called from a callback, so the tick function is still running |
|
80 * and we delay the actual destruction. We ensure no further callbacks will be |
|
81 * sent to prevent surprises. |
|
82 */ |
|
83 clearCallbacks(conn); |
|
84 conn->destroyRequested = true; |
|
85 } else { |
|
86 flib_ipcconn_destroy(&conn->connection); |
|
87 flib_vector_destroy(&conn->configBuffer); |
|
88 free(conn); |
|
89 } |
|
90 } |
|
91 } |
|
92 |
|
93 int flib_mapconn_getport(flib_mapconn *conn) { |
|
94 if(!conn) { |
|
95 flib_log_e("null parameter in flib_mapconn_getport"); |
|
96 return 0; |
|
97 } else { |
|
98 return flib_ipcconn_port(conn->connection); |
|
99 } |
|
100 } |
|
101 |
|
102 void flib_mapconn_onSuccess(flib_mapconn *conn, void (*callback)(void* context, const uint8_t *bitmap, int numHedgehogs), void *context) { |
|
103 if(!conn) { |
|
104 flib_log_e("null parameter in flib_mapconn_onSuccess"); |
|
105 } else { |
|
106 conn->onSuccessCb = callback ? callback : &noop_handleSuccess; |
|
107 conn->onSuccessCtx = context; |
|
108 } |
|
109 } |
|
110 |
|
111 void flib_mapconn_onFailure(flib_mapconn *conn, void (*callback)(void* context, const char *errormessage), void *context) { |
|
112 if(!conn) { |
|
113 flib_log_e("null parameter in flib_mapconn_onError"); |
|
114 } else { |
|
115 conn->onFailureCb = callback ? callback : &noop_handleFailure; |
|
116 conn->onFailureCtx = context; |
|
117 } |
|
118 } |
|
119 |
|
120 static void flib_mapconn_wrappedtick(flib_mapconn *conn) { |
|
121 if(conn->progress == AWAIT_CONNECTION) { |
|
122 flib_ipcconn_accept(conn->connection); |
|
123 switch(flib_ipcconn_state(conn->connection)) { |
|
124 case IPC_CONNECTED: |
|
125 { |
|
126 flib_constbuffer configBuffer = flib_vector_as_constbuffer(conn->configBuffer); |
|
127 if(flib_ipcconn_send_raw(conn->connection, configBuffer.data, configBuffer.size)) { |
|
128 conn->progress = FINISHED; |
|
129 conn->onFailureCb(conn->onFailureCtx, "Error sending map information to the engine."); |
|
130 return; |
|
131 } else { |
|
132 conn->progress = AWAIT_REPLY; |
|
133 } |
|
134 } |
|
135 break; |
|
136 case IPC_NOT_CONNECTED: |
|
137 conn->progress = FINISHED; |
|
138 conn->onFailureCb(conn->onFailureCtx, "Engine connection closed unexpectedly."); |
|
139 return; |
|
140 default: |
|
141 break; |
|
142 } |
|
143 } |
|
144 |
|
145 if(conn->progress == AWAIT_REPLY) { |
|
146 if(flib_ipcconn_recv_map(conn->connection, conn->mapBuffer) >= 0) { |
|
147 conn->progress = FINISHED; |
|
148 conn->onSuccessCb(conn->onSuccessCtx, conn->mapBuffer, conn->mapBuffer[IPCCONN_MAPMSG_BYTES-1]); |
|
149 return; |
|
150 } else if(flib_ipcconn_state(conn->connection) != IPC_CONNECTED) { |
|
151 conn->progress = FINISHED; |
|
152 conn->onFailureCb(conn->onSuccessCtx, "Engine connection closed unexpectedly."); |
|
153 return; |
|
154 } |
|
155 } |
|
156 } |
|
157 |
|
158 void flib_mapconn_tick(flib_mapconn *conn) { |
|
159 if(!conn) { |
|
160 flib_log_e("null parameter in flib_mapconn_tick"); |
|
161 } else if(conn->running) { |
|
162 flib_log_w("Call to flib_mapconn_tick from a callback"); |
|
163 } else if(conn->progress == FINISHED) { |
|
164 flib_log_w("Call to flib_mapconn_tick, but we are already done. Best destroy your flib_mapconn object in the callbacks."); |
|
165 } else { |
|
166 conn->running = true; |
|
167 flib_mapconn_wrappedtick(conn); |
|
168 conn->running = false; |
|
169 |
|
170 if(conn->destroyRequested) { |
|
171 flib_mapconn_destroy(conn); |
|
172 } |
|
173 } |
|
174 } |