-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathclient.c
More file actions
240 lines (211 loc) · 10.5 KB
/
client.c
File metadata and controls
240 lines (211 loc) · 10.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
#include "schema_types.h"
#include <improbable/c_schema.h>
#include <improbable/c_worker.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
char* GenerateWorkerId(char* worker_id_prefix) {
/* Calculate buffer size. */
char* fmt = "%s%d";
int id = rand() % 10000000;
int size = snprintf(NULL, 0, fmt, worker_id_prefix, id);
/* Format string. */
char* worker_id = malloc(sizeof(char) * (size + 1));
sprintf(worker_id, fmt, worker_id_prefix, id);
return worker_id;
}
/** Op handler functions. */
void OnLogMessage(const Worker_LogMessageOp* op) {
printf("log: %s\n", op->message);
}
void OnDisconnect(const Worker_DisconnectOp* op) {
printf("disconnected. reason: %s\n", op->reason);
}
void OnEntityQueryResponse(const Worker_EntityQueryResponseOp* op) {
printf("entity query result: %d entities. Status: %d. Results: %p\n", op->result_count,
op->status_code, (void*)op->results);
if (op->results) {
for (uint32_t i = 0; i < op->result_count; ++i) {
const Worker_Entity* entity = &op->results[i];
printf("- entity %" PRId64 " with %d components", entity->entity_id, entity->component_count);
for (uint32_t i = 0; i < entity->component_count; ++i) {
if (entity->components[i].component_id == POSITION_COMPONENT_ID) {
Improbable_Position* position = (Improbable_Position*)entity->components[i].user_handle;
printf(": Position: (%f, %f, %f)\n", position->coords.x, position->coords.y,
position->coords.z);
}
}
if (entity->component_count == 0) {
printf("\n");
}
}
}
}
void OnAddComponent(const Worker_AddComponentOp* op) {
printf("received add component op (entity: %" PRId64 ", component: %d)\n", op->entity_id,
op->data.component_id);
if (op->data.component_id == POSITION_COMPONENT_ID) {
/* Received position data */
Improbable_Position* position = (Improbable_Position*)op->data.user_handle;
printf("received improbable.Position initial data: (%f, %f, %f)\n", position->coords.x,
position->coords.y, position->coords.z);
}
}
void OnComponentUpdate(const Worker_ComponentUpdateOp* op) {
printf("received component update op (entity: %" PRId64 ", component: %d)\n", op->entity_id,
op->update.component_id);
if (op->update.component_id == POSITION_COMPONENT_ID) {
/* Received position update */
Improbable_PositionUpdate* position = (Improbable_PositionUpdate*)op->update.user_handle;
if (position->coords) {
printf("received improbable.Position update: (%f, %f, %f)\n", position->coords->x,
position->coords->y, position->coords->z);
}
}
}
void OnCommandRequest(Worker_Connection* connection, const Worker_CommandRequestOp* op) {
Schema_FieldId command_index = op->request.command_index;
printf("received command request (entity: %" PRId64 ", component: %d, command: %d).\n",
op->entity_id, op->request.component_id, command_index);
if (op->request.component_id == CLIENTDATA_COMPONENT_ID && command_index == 1) {
Sample_AddCommandRequest* request =
(Sample_AddCommandRequest*)((GenericCommandObject*)op->request.user_handle)->data;
Sample_AddCommandResponse response_data;
response_data.sum = request->payload1 + request->payload2;
Worker_CommandResponse response = {0};
response.command_index = command_index;
response.component_id = op->request.component_id;
response.user_handle = CreateCommandObject(1, &response_data);
Worker_Connection_SendCommandResponse(connection, op->request_id, &response);
free(response.user_handle);
printf("sending command response. Sum: %f\n", response_data.sum);
}
}
int main(int argc, char** argv) {
srand(time(NULL));
if (argc != 4) {
printf("Usage: %s <hostname> <port> <worker_id>\n", argv[0]);
printf("Connects to SpatialOS\n");
printf(" <hostname> - hostname of the receptionist to connect to.\n");
printf(" <port> - port to use\n");
printf(" <worker_id> - name of the worker assigned by SpatialOS.\n");
return EXIT_FAILURE;
}
/* Set up component vtables. */
Worker_ComponentVtable component_vtables[3] = {0};
/* Generate worker ID. */
char* worker_id = GenerateWorkerId(argv[3]);
/* improbable.Position */
component_vtables[0].component_id = POSITION_COMPONENT_ID;
component_vtables[0].component_data_free = &Improbable_Position_ComponentDataFree;
component_vtables[0].component_data_copy = &Improbable_Position_ComponentDataCopy;
component_vtables[0].component_data_deserialize = &Improbable_Position_ComponentDataDeserialize;
component_vtables[0].component_data_serialize = &Improbable_Position_ComponentDataSerialize;
component_vtables[0].component_update_free = &Improbable_Position_ComponentUpdateFree;
component_vtables[0].component_update_copy = &Improbable_Position_ComponentUpdateCopy;
component_vtables[0].component_update_deserialize =
&Improbable_Position_ComponentUpdateDeserialize;
component_vtables[0].component_update_serialize = &Improbable_Position_ComponentUpdateSerialize;
/* sample.Login */
component_vtables[1].component_id = LOGIN_COMPONENT_ID;
component_vtables[1].command_request_free = &Sample_Login_CommandRequestFree;
component_vtables[1].command_request_copy = &Sample_Login_CommandRequestCopy;
component_vtables[1].command_request_deserialize = &Sample_Login_CommandRequestDeserialize;
component_vtables[1].command_request_serialize = &Sample_Login_CommandRequestSerialize;
component_vtables[1].command_response_free = &Sample_Login_CommandResponseFree;
component_vtables[1].command_response_copy = &Sample_Login_CommandResponseCopy;
component_vtables[1].command_response_deserialize = &Sample_Login_CommandResponseDeserialize;
component_vtables[1].command_response_serialize = &Sample_Login_CommandResponseSerialize;
/* sample.ClientData */
component_vtables[2].component_id = CLIENTDATA_COMPONENT_ID;
component_vtables[2].command_request_free = &Sample_ClientData_CommandRequestFree;
component_vtables[2].command_request_copy = &Sample_ClientData_CommandRequestCopy;
component_vtables[2].command_request_deserialize = &Sample_ClientData_CommandRequestDeserialize;
component_vtables[2].command_request_serialize = &Sample_ClientData_CommandRequestSerialize;
component_vtables[2].command_response_free = &Sample_ClientData_CommandResponseFree;
component_vtables[2].command_response_copy = &Sample_ClientData_CommandResponseCopy;
component_vtables[2].command_response_deserialize = &Sample_ClientData_CommandResponseDeserialize;
component_vtables[2].command_response_serialize = &Sample_ClientData_CommandResponseSerialize;
component_vtables[2].component_data_free = &Sample_ClientData_ComponentDataFree;
component_vtables[2].component_data_copy = &Sample_ClientData_ComponentDataCopy;
component_vtables[2].component_data_deserialize = &Sample_ClientData_ComponentDataDeserialize;
component_vtables[2].component_data_serialize = &Sample_ClientData_ComponentDataSerialize;
component_vtables[2].component_update_free = &Sample_ClientData_ComponentUpdateFree;
component_vtables[2].component_update_copy = &Sample_ClientData_ComponentUpdateCopy;
component_vtables[2].component_update_deserialize = &Sample_ClientData_ComponentUpdateDeserialize;
component_vtables[2].component_update_serialize = &Sample_ClientData_ComponentUpdateSerialize;
/* Connect to SpatialOS. */
Worker_ConnectionParameters params = Worker_DefaultConnectionParameters();
params.worker_type = "client_vtable";
params.network.tcp.multiplex_level = 4;
params.component_vtable_count = sizeof(component_vtables) / sizeof(component_vtables[0]);
params.component_vtables = component_vtables;
Worker_ConnectionFuture* connection_future =
Worker_ConnectAsync(argv[1], (uint16_t)atoi(argv[2]), worker_id, ¶ms);
Worker_Connection* connection = Worker_ConnectionFuture_Get(connection_future, NULL);
Worker_ConnectionFuture_Destroy(connection_future);
free(worker_id);
if (Worker_Connection_GetConnectionStatusCode(connection) !=
WORKER_CONNECTION_STATUS_CODE_SUCCESS) {
printf("failed to connect to receptionist. reason: %s\n",
Worker_Connection_GetConnectionStatusDetailString(connection));
Worker_Connection_Destroy(connection);
return EXIT_FAILURE;
}
/* Send a test message. */
Worker_LogMessage message = {WORKER_LOG_LEVEL_WARN, "Client", "Connected successfully", NULL};
Worker_Connection_SendLogMessage(connection, &message);
/* Send an entity query. */
Worker_EntityQuery query;
query.constraint.constraint_type = WORKER_CONSTRAINT_TYPE_ENTITY_ID;
query.constraint.constraint.entity_id_constraint.entity_id = 1;
query.result_type = WORKER_RESULT_TYPE_SNAPSHOT;
query.snapshot_result_type_component_id_count = 1;
Worker_ComponentId position_component_id = POSITION_COMPONENT_ID;
query.snapshot_result_type_component_ids = &position_component_id;
Worker_Connection_SendEntityQueryRequest(connection, &query, NULL);
/* Take control of the entity. */
Sample_Login_TakeControl_Request take_control_request;
Worker_CommandRequest command_request;
memset(&command_request, 0, sizeof(command_request));
command_request.component_id = LOGIN_COMPONENT_ID;
command_request.command_index = 1;
command_request.user_handle = CreateCommandObject(1, &take_control_request);
Worker_CommandParameters command_parameters;
command_parameters.allow_short_circuit = 0;
Worker_Connection_SendCommandRequest(connection, 1, &command_request, NULL, &command_parameters);
/* Main loop. */
while (1) {
Worker_OpList* op_list = Worker_Connection_GetOpList(connection, 0);
for (size_t i = 0; i < op_list->op_count; ++i) {
Worker_Op* op = &op_list->ops[i];
switch (op->op_type) {
case WORKER_OP_TYPE_DISCONNECT:
OnDisconnect(&op->op.disconnect);
break;
case WORKER_OP_TYPE_LOG_MESSAGE:
OnLogMessage(&op->op.log_message);
break;
case WORKER_OP_TYPE_ENTITY_QUERY_RESPONSE:
OnEntityQueryResponse(&op->op.entity_query_response);
break;
case WORKER_OP_TYPE_ADD_COMPONENT:
OnAddComponent(&op->op.add_component);
break;
case WORKER_OP_TYPE_COMPONENT_UPDATE:
OnComponentUpdate(&op->op.component_update);
break;
case WORKER_OP_TYPE_COMMAND_REQUEST:
OnCommandRequest(connection, &op->op.command_request);
break;
default:
break;
}
}
Worker_OpList_Destroy(op_list);
}
Worker_Connection_Destroy(connection);
return EXIT_SUCCESS;
}