-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathastar.js
381 lines (318 loc) · 13.2 KB
/
astar.js
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
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
/** This script is for the police bot wandering around Oulu 3D.
* @author Lasse Annola <[email protected]>
*/
// Include the json parse/stringify library. We host it here if you want to use it:
// !ref: http://meshmoon.data.s3.amazonaws.com/app/lib/json2.js, Script
// Include our utils script that has asset storage and bytearray utils etc.
// !ref: http://meshmoon.data.s3.amazonaws.com/app/lib/admino-utils-common-deploy.js, Script
// !ref: http://meshmoon.data.s3.amazonaws.com/app/lib/class.js, Script
engine.ImportExtension('qt.core');
engine.IncludeFile("http://meshmoon.data.s3.amazonaws.com/app/lib/class.js");
engine.IncludeFile("http://meshmoon.data.s3.amazonaws.com/app/lib/admino-utils-common-deploy.js");
SetLogChannelName("Police script");
Log("Script starting");
/**
* This script is for the police bot wandering around Oulu 3D.
* @module PoliceScript
*/
/**Variable for parsed Navigation Mesh. Includes x and z coordinates.
* @type Array */
var pathWays;
/** Holder for next destination of movement. Includes x and z coordinates.
* @type Array */
var nextDest;
/** Boolean to check if orientation was already set.
* @type bool */
var orientationSet = false;
/** Player that will be busted by the police.
* @type Object */
var playerToBeBusted;
/** Interval for Update function.
* @type int */
var interval = 0;
/** Current amount of visible polices on script start.
* @type List */
var visiblePolices = scene.EntitiesOfGroup('Polices');
/** Players that have been busted and their data was already sent to server, here to avoid duplicate posts to GameAnalytics.
* @type Array */
var bustedPlayers = [];
/** Boolean to check if Policebot reached movement goal.
* @type bool */
var reachedgoal = true;
/** Get the Navigation Mesh object for the script. Hosted at Meshmoon scene storage. */
var transfer = asset.RequestAsset("http://meshmoon.eu.scenes.2.s3.amazonaws.com/mediateam-b4527d/test2/navmesh/kartta.obj", "Binary", true);
transfer.Succeeded.connect(function(transfer) {
pathWays = parseObjData(transfer);
});
frame.Updated.connect(Update);
/**
* Update function that is ran on every frame.
* @param {int} frametime - Int to check how many frames are through.
*/
function Update (frametime) {
if (!server.IsRunning()) {
/** Monitor players for possible busting. */
MonitorPlayers();
/** Check that pathWays array exists and that current Policebot is not a testbot nor its not visible. */
if(pathWays && this.me.name != 'robotest' && this.me.placeable.visible)
NewDestinationAndMove(pathWays, frametime);
/** Keep animations in sync with events. */
CheckAnims();
if (interval < 150) interval++;
else {
/** Check the amount of policebots on scene according to time TODO: FIX THIX DOES NOT WORK */
MonitorPoliceAmount();
interval = 0;
}
}
}
/**
* Function to monitor police amount in scene. TODO: FIX NOT WORKING
* Should check that time is between 18:00 and 06:00, to add more policebots.
*/
function MonitorPoliceAmount() {
if (new Date().getHours() < 18 && new Date().getHours() > 6) {
if (visiblePolices.length > 2) {
for (var i in visiblePolices) {
visiblePolices[i].placeable.visible = false;
visiblePolices.splice(i, 1);
}
}
} else {
var polices = scene.EntitiesOfGroup('Polices');
for (var i in polices) {
if (visiblePolices.length < 7) {
polices[i].placeable.visible = true;
visiblePolices.push(polices[i]);
}
}
}
}
/**
* Checks if police has no animations active and activates basic walk animation to roll.
*/
function CheckAnims() {
if (this.me.animationcontroller.GetActiveAnimations().length < 1)
this.me.animationcontroller.EnableExclusiveAnimation('walk', true, 1, 1, false);
}
/**
* Gets orientation for the source to a new destination.
* @param {vector3} source - Source entity vector3.
* @param {vector3} destination - Destination entitys vector3
* @returns {Quat} Calculated orientation to new destination in Quat.
*/
function LookAt(source, destination) {
var targetLookAtDir = new float3();
targetLookAtDir.x = destination.x - source.x;
targetLookAtDir.y = destination.y - source.y;
targetLookAtDir.z = destination.z - source.z;
targetLookAtDir.Normalize();
//return Quat.RotateFromTo(source, destination);
return Quat.LookAt(scene.ForwardVector(), targetLookAtDir, scene.UpVector(), scene.UpVector());
}
/**
* New destination for Policebot and the actual movement of the police. Current destination has to be between 25 and 15 meters, can be easily changed in first if structure.
* @param {array} destination - Array full or destinations from navigation mesh.
* @param {int} frametime - Frametime integer used for speed in the actual movement.
*/
function NewDestinationAndMove(destination, frametime) {
//If bot reached its goal, random a new goal and check that its valid.
var tm = this.me.placeable.transform;
if (reachedgoal) {
var nextDesti = destination[random(destination.length)];
xNow = nextDesti[0];
zNow = nextDesti[1];
var dist = Math.sqrt(Math.pow((xNow - this.me.placeable.Position().x), 2) +
Math.pow((zNow - this.me.placeable.Position().z), 2));
if (dist < 25 && dist > 15 && nextDest != nextDesti) {
nextDest = nextDesti;
} else
return;
}
var totalLat=0;
var totalLon=0;
var ratioLat;
var ratioLon;
//Make relative values for walking.
var relativeLon = nextDest[0] - this.me.placeable.Position().x;
var relativeLat = nextDest[1] - this.me.placeable.Position().z;
//Check ratio to walk between x and z axis.
if (Math.abs(relativeLat) >= Math.abs(relativeLon)) {
ratioLon = Math.abs(relativeLon / relativeLat);
ratioLat = 1;
} else {
ratioLat = Math.abs(relativeLat / relativeLon);
ratioLon = 1;
}
var time = frametime;
var speed = 2.0; //Speed value, can be changed to manipulate movement speed.
//Where are we now.
var yNow = this.me.placeable.transform.pos.y;
var xNow = this.me.placeable.transform.pos.x;
var zNow = this.me.placeable.transform.pos.z;
//Movement.
var lats = speed * time * ratioLat;
var lons = speed * time * ratioLon;
//Check in which quad we are moving into.
if (relativeLon >= 0) var finalMovementX = xNow + lons;
else var finalMovementX = xNow - lons;
if (relativeLat >= 0) var finalMovementZ = zNow + lats;
else var finalMovementZ = zNow - lats;
//Add movement value to total position value.
totalLat += lats;
totalLon += lons;
tm.pos.x = finalMovementX;
tm.pos.z = finalMovementZ;
//Assign value to script owner - Police bot
this.me.placeable.transform = tm;
/** Check if orientation was set yet. */
if (!orientationSet) {
this.me.placeable.SetOrientation(LookAt(this.me.placeable.transform.pos,
new float3(xNow, this.me.placeable.transform.pos.y, zNow)));
orientationSet = true;
}
/** Check if we have reached the destination and change reachedgoal to true. */
if (totalLat > Math.abs(relativeLat) || totalLon > Math.abs(relativeLon)) {
reachedgoal = true;
totalLat = 0;
totalLon = 0;
orientationSet = false;
} else
reachedgoal = false;
}
/**
* Parse .obj file so that we get only z and x from vertices. We do not use faces at the moment, or the Y coordinate.
* @param {Object} data - Data of navigation mesh .obj file.
* @returns {array} xNz - X and Z values in Array for police to use as navigation array.
*/
function parseObjData(data) {
//Variables for the function to handle data from server.
var objText = data.RawData();
var verticles;
var obj = {};
var graph;
/* Style what we want to get rid of. So v X,Y,Z, in each ro we take x and z*/
var vertexMatches = QByteArrayToString(objText).match(/^v( -?\d+(\.\d+)?){3}$/gm);
var result;
var values = String(vertexMatches).split(",");
var xNz = [];
/* Take v from file and replace with empty. */
for (i = 0; i < values.length; i++) {
values[i] = String(values[i]).replace('v ', '');
}
/* Split every row from " " */
for (i = 0; i < values.length; i++) {
values[i] = String(values[i]).split(" ");
}
if (values) {
obj = values.map(function(vertex)
{
vertex.splice(1, 1);
values = vertex;
xNz.push(values);
});
}
return xNz;
}
/**
* Monitors players in the scene and busts the ones within 15 meters. In if statement its easy to change busting value in meters.
*/
function MonitorPlayers() {
var Players = scene.EntitiesOfGroup('Player');
for (var i in Players) {
var json = null;
var x = this.me.placeable.Position().x;
var z = this.me.placeable.Position().z;
//Calculating distance.
var distance = Math.sqrt(Math.pow((x - Players[i].placeable.Position().x), 2) +
Math.pow((z - Players[i].placeable.Position().z), 2));
if (Players[i].dynamiccomponent.GetAttribute('spraying')) {
if (distance < 15) {
playerToBeBusted = Players[i];
http.client.Get("http://vm0063.virtues.fi/gangsters/").Finished.connect(function(req, status, error) {
if (status == 200) {
UploadBustedPlayers(req.body);
}
});
} else
continue;
}
}
}
/**
* Monitors players in the scene and busts the ones within 15 meters. In if statement its easy to change busting value in meters.
* Send busted players to the GameAnalytics with some data from them.
* @param {JSONArray} players - Players in SAG as JSON array to be parsed.
*/
function UploadBustedPlayers(players) {
if (players.RawData() == [] || players.RawData() == "" || !players)
return;
var playerId = null;
var playersToString = QByteArrayToString(players.RawData());
var json = JSON.parse(playersToString);
if(!json) return;
for (var i in json) {
/** Check if player that was busted is in our players, if so check also that player info was not already sent to GameAnalytics. */
if (json[i].username == playerToBeBusted.name) {
for (var i in bustedPlayers) {
if (playerToBeBusted.name == bustedPlayers[i]) return;
}
playerId = json[i].id;
} else {
/** If no player is busted check for sent players and remove possible sent players from the array, since the player is not busted anymore. */
for (var i in bustedPlayers)
if (bustedPlayers[i] == json[i].username)
bustedPlayers.splice(bustedPlayers[i], 1);
continue;
}
}
var jsonNew = JSON.stringify(json);
var qByteJson = EncodeString('UTF-8', json);
if (jsonNew && playerId) {
//Animate player and police for busting.
this.me.animationcontroller.PlayAnim('busted', 0, 'busted');
playerToBeBusted.dynamiccomponent.SetAttribute('spraying', false);
playerToBeBusted.animationcontroller.EnableExclusiveAnimation('busted', false, 1, 1, false);
playerToBeBusted.animationcontroller.AnimationFinished.connect(function(){
this.me.animationcontroller.StopAllAnims(0);
this.me.animationcontroller.PlayLoopedAnim('walk', 0, 'walk');
});
if (!playerId) return;
/** Send player to our middle server to remove points from player and add busted information. */
http.client.Get("http://vm0063.virtues.fi/police/" + playerId + "/").Finished.connect(function(req, status, error) {
if (status == 200)
Log('Police busted succesfully.');
});
var pos = String(this.me.placeable.transform.pos.x) + ',' + String(this.me.placeable.transform.pos.y) + ',' + String(this.me.placeable.transform.pos.z);
pos = pos.split(",").join('%2C');
http.client.Get("http://vm0063.virtues.fi/events/" + String(8) + "/playername" + '/' + "Police" + "/" + "playerpos/" + pos + '/playerinfo' + '/' + "Police"
+ '/playerdata' + '/' + String(123) + '/').Finished.connect(function(req, status, error) {
if (status == 200) {
bustedPlayers.push(json[i].username);
}
});
}
}
/* Json encoding and decoding functions. **/
function QByteArrayToString(qbytearray)
{
var ts = new QTextStream(qbytearray, QIODevice.ReadOnly);
return ts.readAll();
}
function DecodeString(encoding, qbytearray)
{
var strEncoding = new QByteArray(encoding);
var codec = QTextCodec.codecForName(strEncoding);
return codec.toUnicode(qbytearray);
}
function EncodeString(encoding, string)
{
var strEncoding = new QByteArray(encoding);
var codec = QTextCodec.codecForName(strEncoding);
return codec.fromUnicode(string);
}
function random(n) {
seed = new Date().getTime();
seed = (seed*9301+49297) % 233280;
return (Math.floor((seed/(233280.0)* n)));
}