Commit 58c95f1c authored by Roque's avatar Roque

erp5_officejs_drone_capture_flag: changes on the game

- add back the drone collision logic
- check drone out with map limits
- randomize seed library
- use seed to randomize values
- terrain texture change
- adapt default configuration
- refactor to allow map_size as parameter (instead of min-max lat-lon)
- new map function
- camera and size limits
- enemy team
- enemy AI script
- add flags and obstacles
- obstacle and flag collision
- allow dronemanager to take cartesian coordinates
- game finish rulls
- user score and result message
- refactor AI default script (drone dodges obstacles)
- new drone implementation for enemy drone (API)
- add getDroneViewInfo to API(s)
- restore drone color dot trace (improve color pick)
- allow random seed as url parameter
- handle fullscreen
- flag weight as parameter
- show default seed value, and make input mandatory
- do not show enemy drone logs on UI
- flag collision crashes the drone
- update score calculation
- drop flag weight (model and parameter)
- use geo coordinates in general
- refactor enemy drone to use cartesian
- add debug mode for test using console logs
- async obstacle detection (API changes)
parent a5c95ebd
/*global BABYLON, console*/
/*jslint nomen: true, indent: 2, maxlen: 80, todo: true */
/************************** ENEMY DRONE API ****************************/
var EnemyDroneAPI = /** @class */ (function () {
"use strict";
var DEFAULT_ACCELERATION = 1,
VIEW_SCOPE = 50,
DEFAULT_SPEED = 16.5,
MIN_SPEED = 12,
MAX_SPEED = 26;
//** CONSTRUCTOR
function EnemyDroneAPI(gameManager, drone_info, flight_parameters, id) {
this._gameManager = gameManager;
this._mapManager = this._gameManager._mapManager;
this._map_dict = this._mapManager.getMapInfo();
this._flight_parameters = flight_parameters;
this._id = id;
this._drone_info = drone_info;
this._drone_dict_list = [];
this._acceleration = DEFAULT_ACCELERATION;
}
/*
** Function called on start phase of the drone, just before onStart AI script
*/
EnemyDroneAPI.prototype.internal_start = function (drone) {
drone._targetCoordinates = drone.getCurrentPosition();
drone._maxAcceleration = this.getMaxAcceleration();
if (drone._maxAcceleration <= 0) {
throw new Error('max acceleration must be superior to 0');
}
drone._minSpeed = this.getMinSpeed();
if (drone._minSpeed <= 0) {
throw new Error('min speed must be superior to 0');
}
drone._maxSpeed = this.getMaxSpeed();
if (drone._minSpeed > drone._maxSpeed) {
throw new Error('min speed cannot be superior to max speed');
}
drone._speed = drone._targetSpeed = this.getInitialSpeed();
if (drone._speed < drone._minSpeed || drone._speed > drone._maxSpeed) {
throw new Error('Drone speed must be between min speed and max speed');
}
if (drone._maxSinkRate > drone._maxSpeed) {
throw new Error('max sink rate cannot be superior to max speed');
}
drone._maxOrientation = this.getMaxOrientation();
return;
};
/*
** Function called on every drone update, right before onUpdate AI script
*/
EnemyDroneAPI.prototype.internal_update = function (context, delta_time) {
context._speed += context._acceleration * delta_time / 1000;
if (context._speed > context._maxSpeed)
context._speed = context._maxSpeed;
if (context._speed < -context._maxSpeed)
context._speed = -context._maxSpeed;
var updateSpeed = context._speed * delta_time / 1000;
if (context._direction.x !== 0 ||
context._direction.y !== 0 ||
context._direction.z !== 0) {
context._controlMesh.position.addInPlace(
new BABYLON.Vector3(context._direction.x * updateSpeed,
context._direction.y * updateSpeed,
context._direction.z * updateSpeed));
}
var orientationValue = context._maxOrientation *
(context._speed / context._maxSpeed);
context._mesh.rotation = new BABYLON.Vector3(
orientationValue * context._direction.z, 0,
-orientationValue * context._direction.x);
context._controlMesh.computeWorldMatrix(true);
context._mesh.computeWorldMatrix(true);
return;
};
/*
** Function called on every drone update, right after onUpdate AI script
*/
EnemyDroneAPI.prototype.internal_post_update = function (drone) {
var _this = this, drone_position = drone.getCurrentPosition(), drone_info;
if (drone_position) {
drone_info = {
'altitudeRel' : drone_position.z,
'altitudeAbs' : _this._mapManager.getMapInfo().start_AMSL +
drone_position.z,
'latitude' : drone_position.x,
'longitude' : drone_position.y
};
_this._drone_dict_list[_this._id] = drone_info;
//broadcast drone info using internal msg
_this._gameManager._droneList.forEach(function (drone) {
if (drone.id !== _this._id) {
drone.internal_getMsg(drone_info, _this._id);
}
});
}
};
EnemyDroneAPI.prototype.setAltitude = function (drone, altitude) {
drone._targetCoordinates.z = altitude;
};
EnemyDroneAPI.prototype.setStartingPosition = function (drone, x, y, z) {
if (!drone._canPlay) {
if (z <= 0.05) {
z = 0.05;
}
drone._controlMesh.position = new BABYLON.Vector3(x, z, y);
}
drone._controlMesh.computeWorldMatrix(true);
drone._mesh.computeWorldMatrix(true);
};
EnemyDroneAPI.prototype.internal_getMsg = function (msg, id) {
this._drone_dict_list[id] = msg;
};
EnemyDroneAPI.prototype.internal_setTargetCoordinates =
function (drone, coordinates) {
if (!drone._canPlay) return;
var x = coordinates.x, y = coordinates.y, z = coordinates.z;
if (isNaN(x) || isNaN(y) || isNaN(z)) {
throw new Error('Target coordinates must be numbers');
}
x -= drone._controlMesh.position.x;
y -= drone._controlMesh.position.z;
z -= drone._controlMesh.position.y;
drone.setDirection(x, y, z);
};
EnemyDroneAPI.prototype.sendMsg = function (msg, to) {
var _this = this,
droneList = _this._gameManager._droneList;
_this._gameManager.delay(function () {
if (to < 0) {
// Send to all drones
droneList.forEach(function (drone) {
if (drone.infosMesh) {
try {
drone.onGetMsg(msg);
} catch (error) {
console.warn('Drone crashed on sendMsg due to error:', error);
drone._internal_crash();
}
}
});
} else {
// Send to specific drone
if (droneList[to].infosMesh) {
try {
droneList[to].onGetMsg(msg);
} catch (error) {
console.warn('Drone crashed on sendMsg due to error:', error);
droneList[to]._internal_crash();
}
}
}
}, _this._flight_parameters.latency.communication);
};
EnemyDroneAPI.prototype.log = function (msg) {
console.log("API say : " + msg);
};
EnemyDroneAPI.prototype.getGameParameter = function (name) {
if (["gameTime", "map"].includes(name)) {
return this._gameManager.gameParameter[name];
}
};
/*
** Enemy drone works with cartesian, no geo conversion
*/
EnemyDroneAPI.prototype.processCoordinates = function (x, y, z) {
if (isNaN(x) || isNaN(y) || isNaN(z)) {
throw new Error('Target coordinates must be numbers');
}
if (z > this._map_dict.start_AMSL) {
z -= this._map_dict.start_AMSL;
}
return {
'x': x,
'y': y,
'z': z
};
};
EnemyDroneAPI.prototype.getCurrentPosition = function (x, y, z) {
return this._mapManager.convertToGeoCoordinates(x, y, z);
};
EnemyDroneAPI.prototype.getDroneViewInfo = function (drone) {
var context = this, result = [], distance,
drone_position = drone.position, other_position;
function calculateDistance(a, b) {
return Math.sqrt(Math.pow((a.x - b.x), 2) + Math.pow((a.y - b.y), 2) +
Math.pow((a.z - b.z), 2));
}
context._gameManager._droneList_user.forEach(function (other) {
if (other.can_play) {
other_position = other.position;
distance = calculateDistance(drone_position, other_position);
if (distance <= VIEW_SCOPE) {
result.push({
position: other_position,
direction: other.direction,
rotation: other.rotation,
speed: other.speed,
target: other._targetCoordinates, //check
team: other.team
});
}
}
});
return result;
};
EnemyDroneAPI.prototype.getDroneAI = function () {
//interception math based on https://www.codeproject.com/Articles/990452/Interception-of-Two-Moving-Objects-in-D-Space
return 'var BASE_DISTANCE = 300;\n' +
'function calculateInterception(hunter_position, prey_position, hunter_speed, prey_speed, prey_velocity_vector) {\n' +
' var vector_from_drone, distance_to_prey, distance_to_prey_vector, a, b, c, t1, t2, interception_time, interception_point;\n' +
' function dot(a, b) {\n' +
' return a.map((x, i) => a[i] * b[i]).reduce((m, n) => m + n);\n' +
' }\n' +
' distance_to_prey_vector = [hunter_position.x - prey_position.x, hunter_position.y - prey_position.y, hunter_position.z - prey_position.z];\n' +
' distance_to_prey = distance(hunter_position, prey_position);\n' +
' a = hunter_speed * hunter_speed - prey_speed * prey_speed;\n' +
' b = 2 * dot(distance_to_prey_vector, prey_velocity_vector);\n' +
' c = - distance_to_prey * distance_to_prey;\n' +
' t1 = (-b + Math.sqrt(b * b - 4 * a * c)) / (2 * a);\n' +
' t2 = (-b - Math.sqrt(b * b - 4 * a * c)) / (2 * a);\n' +
' if (t1 > 0 && t2 > 0) {\n' +
' interception_time = Math.min( t1, t2 );\n' +
' } else {\n' +
' interception_time = Math.max( t1, t2 );\n' +
' }\n' +
' interception_point = [prey_position.x + prey_velocity_vector[0] * interception_time, prey_position.y + prey_velocity_vector[1] * interception_time, prey_position.z + prey_velocity_vector[2] * interception_time];\n' +
' if (isNaN(interception_point[0]) || isNaN(interception_point[1]) || isNaN(interception_point[2])) {\n' +
' return;\n' +
' }\n' +
' return interception_point;\n' +
'}\n' +
'function distance(a, b) {\n' +
' return Math.sqrt((a.x - b.x) ** 2 + (a.y - b.y) ** 2 + (a.z - b.z) ** 2);\n' +
'}\n' +
'\n' +
'me.onStart = function () {\n' +
' me.base = me.position;\n' +
' me.setDirection(0,0,0);\n' +
' return;\n' +
'\n' +
'};\n' +
'\n' +
'me.onUpdate = function (timestamp) {\n' +
' me.current_position = me.position;\n' +
' var drone_position, drone_velocity_vector, interception_point, drone_view,\n' +
' dist = distance(\n' +
' me.current_position,\n' +
' me.base\n' +
' );\n' +
// return to base point if drone is too far
' if (dist >= BASE_DISTANCE) {\n' +
' me.chasing = false;\n' +
' me.setTargetCoordinates(\n' +
' me.base.x,\n' +
' me.base.y,\n' +
' me.base.z\n' +
' );\n' +
' return;\n' +
' }\n' +
' drone_view = me.getDroneViewInfo();\n' +
' if (drone_view.length) {\n' +
' drone_position = drone_view[0].position;\n' +
' drone_velocity_vector = [drone_view[0].target.x - drone_position.x, drone_view[0].target.y - drone_position.y, drone_view[0].target.z - drone_position.z];\n' +
' interception_point = calculateInterception(me.current_position, drone_position, me.speed, drone_view[0].speed, drone_velocity_vector);\n' +
' if (!interception_point) {\n' +
' return;\n' +
' }\n' +
' me.chasing = true;\n' +
' me.setTargetCoordinates(interception_point[0], interception_point[1], interception_point[2]);\n' +
' }\n' +
// return to base point if drone is too far
' if (!me.chasing && dist <= 10) {\n' +
' me.setDirection(0,0,0);\n' +
' }\n' +
'};';
};
EnemyDroneAPI.prototype.getMinSpeed = function () {
return MIN_SPEED;
//return this._flight_parameters.drone.minSpeed;
};
EnemyDroneAPI.prototype.getMaxSpeed = function () {
return MAX_SPEED;
//return this._flight_parameters.drone.maxSpeed;
};
EnemyDroneAPI.prototype.getInitialSpeed = function () {
return DEFAULT_SPEED;
//return this._flight_parameters.drone.speed;
};
EnemyDroneAPI.prototype.getMaxDeceleration = function () {
return this._flight_parameters.drone.maxDeceleration;
};
EnemyDroneAPI.prototype.getMaxAcceleration = function () {
return this._flight_parameters.drone.maxAcceleration;
};
EnemyDroneAPI.prototype.getMaxOrientation = function () {
//TODO should be a game parameter (but how to force value to PI quarters?)
return Math.PI / 4;
};
EnemyDroneAPI.prototype.triggerParachute = function (drone) {
var drone_pos = drone.getCurrentPosition();
drone.setTargetCoordinates(drone_pos.x, drone_pos.y, 5);
};
EnemyDroneAPI.prototype.landed = function (drone) {
var drone_pos = drone.getCurrentPosition();
return Math.floor(drone_pos.z) < 10;
};
EnemyDroneAPI.prototype.exit = function () {
return;
};
EnemyDroneAPI.prototype.getInitialAltitude = function () {
return 0;
};
EnemyDroneAPI.prototype.getAltitudeAbs = function (altitude) {
return altitude;
};
EnemyDroneAPI.prototype.getMinHeight = function () {
return 0;
};
EnemyDroneAPI.prototype.getMaxHeight = function () {
return 800;
};
EnemyDroneAPI.prototype.getFlightParameters = function () {
return this._flight_parameters;
};
return EnemyDroneAPI;
}());
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Web Script" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_Access_contents_information_Permission</string> </key>
<value>
<tuple>
<string>Anonymous</string>
<string>Assignee</string>
<string>Assignor</string>
<string>Associate</string>
<string>Auditor</string>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>_Add_portal_content_Permission</string> </key>
<value>
<tuple>
<string>Assignee</string>
<string>Assignor</string>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>_Change_local_roles_Permission</string> </key>
<value>
<tuple>
<string>Assignor</string>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>_Modify_portal_content_Permission</string> </key>
<value>
<tuple>
<string>Assignee</string>
<string>Assignor</string>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>_View_Permission</string> </key>
<value>
<tuple>
<string>Anonymous</string>
<string>Assignee</string>
<string>Assignor</string>
<string>Associate</string>
<string>Auditor</string>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>content_md5</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>content_type</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>default_reference</string> </key>
<value> <string>gadget_erp5_page_drone_capture_flag_enemydrone.js</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>drone_capture_flag_enemydrone_js</string> </value>
</item>
<item>
<key> <string>language</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Web Script</string> </value>
</item>
<item>
<key> <string>short_title</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Enemy Drone (API)</string> </value>
</item>
<item>
<key> <string>version</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>workflow_history</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary>
<item>
<key> <string>document_publication_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
<item>
<key> <string>edit_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAQ=</string> </persistent>
</value>
</item>
<item>
<key> <string>processing_status_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAU=</string> </persistent>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_log</string> </key>
<value>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>publish_alive</string> </value>
</item>
<item>
<key> <string>actor</string> </key>
<value> <unicode>zope</unicode> </value>
</item>
<item>
<key> <string>comment</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>error_message</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>time</string> </key>
<value>
<object>
<klass>
<global name="_reconstructor" module="copy_reg"/>
</klass>
<tuple>
<global name="DateTime" module="DateTime.DateTime"/>
<global name="object" module="__builtin__"/>
<none/>
</tuple>
<state>
<tuple>
<float>1683915732.9</float>
<string>UTC</string>
</tuple>
</state>
</object>
</value>
</item>
<item>
<key> <string>validation_state</string> </key>
<value> <string>published_alive</string> </value>
</item>
</dictionary>
</list>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="4" aka="AAAAAAAAAAQ=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_log</string> </key>
<value>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>edit</string> </value>
</item>
<item>
<key> <string>actor</string> </key>
<value> <unicode>zope</unicode> </value>
</item>
<item>
<key> <string>comment</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>error_message</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>serial</string> </key>
<value> <string>1009.37360.49772.3874</string> </value>
</item>
<item>
<key> <string>state</string> </key>
<value> <string>current</string> </value>
</item>
<item>
<key> <string>time</string> </key>
<value>
<object>
<klass>
<global name="_reconstructor" module="copy_reg"/>
</klass>
<tuple>
<global name="DateTime" module="DateTime.DateTime"/>
<global name="object" module="__builtin__"/>
<none/>
</tuple>
<state>
<tuple>
<float>1688571911.82</float>
<string>UTC</string>
</tuple>
</state>
</object>
</value>
</item>
</dictionary>
</list>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="5" aka="AAAAAAAAAAU=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_log</string> </key>
<value>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>detect_converted_file</string> </value>
</item>
<item>
<key> <string>actor</string> </key>
<value> <unicode>zope</unicode> </value>
</item>
<item>
<key> <string>comment</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>error_message</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>external_processing_state</string> </key>
<value> <string>converted</string> </value>
</item>
<item>
<key> <string>serial</string> </key>
<value> <string>0.0.0.0</string> </value>
</item>
<item>
<key> <string>time</string> </key>
<value>
<object>
<klass>
<global name="_reconstructor" module="copy_reg"/>
</klass>
<tuple>
<global name="DateTime" module="DateTime.DateTime"/>
<global name="object" module="__builtin__"/>
<none/>
</tuple>
<state>
<tuple>
<float>1683913977.2</float>
<string>UTC</string>
</tuple>
</state>
</object>
</value>
</item>
</dictionary>
</list>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -5,12 +5,9 @@ ...@@ -5,12 +5,9 @@
var FixedWingDroneAPI = /** @class */ (function () { var FixedWingDroneAPI = /** @class */ (function () {
"use strict"; "use strict";
// var TAKEOFF_RADIUS = 60,
var DEFAULT_SPEED = 16, var DEFAULT_SPEED = 16,
EARTH_GRAVITY = 9.81, EARTH_GRAVITY = 9.81,
LOITER_LIMIT = 30, LOITER_LIMIT = 30,
LOITER_RADIUS_FACTOR = 0.60,
LOITER_SPEED_FACTOR = 1.5,
MAX_ACCELERATION = 6, MAX_ACCELERATION = 6,
MAX_DECELERATION = 1, MAX_DECELERATION = 1,
MIN_SPEED = 12, MIN_SPEED = 12,
...@@ -19,7 +16,8 @@ var FixedWingDroneAPI = /** @class */ (function () { ...@@ -19,7 +16,8 @@ var FixedWingDroneAPI = /** @class */ (function () {
MIN_PITCH = -20, MIN_PITCH = -20,
MAX_PITCH = 25, MAX_PITCH = 25,
MAX_CLIMB_RATE = 8, MAX_CLIMB_RATE = 8,
MAX_SINK_RATE = 3; MAX_SINK_RATE = 3,
VIEW_SCOPE = 100;
//** CONSTRUCTOR //** CONSTRUCTOR
function FixedWingDroneAPI(gameManager, drone_info, flight_parameters, id) { function FixedWingDroneAPI(gameManager, drone_info, flight_parameters, id) {
...@@ -29,10 +27,8 @@ var FixedWingDroneAPI = /** @class */ (function () { ...@@ -29,10 +27,8 @@ var FixedWingDroneAPI = /** @class */ (function () {
this._flight_parameters = flight_parameters; this._flight_parameters = flight_parameters;
this._id = id; this._id = id;
this._drone_info = drone_info; this._drone_info = drone_info;
this._loiter_radius = 0; this._loiter_radius = 100;
this._last_loiter_point_reached = -1;
//this._start_altitude = 0; //this._start_altitude = 0;
//this._last_altitude_point_reached = -1;
this._loiter_mode = false; this._loiter_mode = false;
this._drone_dict_list = []; this._drone_dict_list = [];
} }
...@@ -40,6 +36,7 @@ var FixedWingDroneAPI = /** @class */ (function () { ...@@ -40,6 +36,7 @@ var FixedWingDroneAPI = /** @class */ (function () {
** Function called on start phase of the drone, just before onStart AI script ** Function called on start phase of the drone, just before onStart AI script
*/ */
FixedWingDroneAPI.prototype.internal_start = function (drone) { FixedWingDroneAPI.prototype.internal_start = function (drone) {
drone._targetCoordinates = drone.getCurrentPosition();
drone._maxDeceleration = this.getMaxDeceleration(); drone._maxDeceleration = this.getMaxDeceleration();
if (drone._maxDeceleration <= 0) { if (drone._maxDeceleration <= 0) {
throw new Error('max deceleration must be superior to 0'); throw new Error('max deceleration must be superior to 0');
...@@ -146,9 +143,6 @@ var FixedWingDroneAPI = /** @class */ (function () { ...@@ -146,9 +143,6 @@ var FixedWingDroneAPI = /** @class */ (function () {
*/ */
FixedWingDroneAPI.prototype.internal_post_update = function (drone) { FixedWingDroneAPI.prototype.internal_post_update = function (drone) {
var _this = this, drone_position = drone.getCurrentPosition(), drone_info; var _this = this, drone_position = drone.getCurrentPosition(), drone_info;
if (_this._loiter_mode) {
_this.loiter(drone);
}
/*if (_this._start_altitude > 0) { //TODO move start_altitude here /*if (_this._start_altitude > 0) { //TODO move start_altitude here
_this.reachAltitude(drone); _this.reachAltitude(drone);
}*/ }*/
...@@ -158,7 +152,10 @@ var FixedWingDroneAPI = /** @class */ (function () { ...@@ -158,7 +152,10 @@ var FixedWingDroneAPI = /** @class */ (function () {
'altitudeAbs' : _this._mapManager.getMapInfo().start_AMSL + 'altitudeAbs' : _this._mapManager.getMapInfo().start_AMSL +
drone_position.z, drone_position.z,
'latitude' : drone_position.x, 'latitude' : drone_position.x,
'longitude' : drone_position.y 'longitude' : drone_position.y,
'yaw': drone.getYaw(),
'speed': drone.getAirSpeed(),
'climbRate': drone.getClimbRate()
}; };
_this._drone_dict_list[_this._id] = drone_info; _this._drone_dict_list[_this._id] = drone_info;
//broadcast drone info using internal msg //broadcast drone info using internal msg
...@@ -171,7 +168,7 @@ var FixedWingDroneAPI = /** @class */ (function () { ...@@ -171,7 +168,7 @@ var FixedWingDroneAPI = /** @class */ (function () {
}; };
FixedWingDroneAPI.prototype._updateSpeed = function (drone, delta_time) { FixedWingDroneAPI.prototype._updateSpeed = function (drone, delta_time) {
var speed = drone.getSpeed(), speedDiff, speedUpdate; var speed = drone.getAirSpeed(), speedDiff, speedUpdate;
if (speed !== this._targetSpeed) { if (speed !== this._targetSpeed) {
speedDiff = this._targetSpeed - speed; speedDiff = this._targetSpeed - speed;
speedUpdate = drone._acceleration * delta_time / 1000; speedUpdate = drone._acceleration * delta_time / 1000;
...@@ -185,13 +182,30 @@ var FixedWingDroneAPI = /** @class */ (function () { ...@@ -185,13 +182,30 @@ var FixedWingDroneAPI = /** @class */ (function () {
}; };
FixedWingDroneAPI.prototype._updateDirection = function (drone, delta_time) { FixedWingDroneAPI.prototype._updateDirection = function (drone, delta_time) {
var horizontalCoeff, newX, newY, newZ; var horizontalCoeff, newX, newY, newZ, tangentYaw;
if (this._loiter_mode && Math.sqrt(
Math.pow(drone._targetCoordinates.x - drone.position.x, 2) +
Math.pow(drone._targetCoordinates.y - drone.position.y, 2)
) <= this._loiter_radius) {
tangentYaw = this._computeBearing(
drone.position.x,
drone.position.y,
drone._targetCoordinates.x,
drone._targetCoordinates.y
) - 90;
// trigonometric circle is east oriented, yaw angle is clockwise
tangentYaw = this._toRad(-tangentYaw + 90);
newX = Math.cos(tangentYaw);
newZ = Math.sin(tangentYaw);
} else {
[newX, newZ] = this._getNewYaw(drone, delta_time); [newX, newZ] = this._getNewYaw(drone, delta_time);
}
newY = this._getNewAltitude(drone); newY = this._getNewAltitude(drone);
horizontalCoeff = Math.sqrt( horizontalCoeff = Math.sqrt(
( (
Math.pow(drone.getSpeed(), 2) - Math.pow(newY, 2) Math.pow(drone.getAirSpeed(), 2) - Math.pow(newY, 2)
) / ( ) / (
Math.pow(newX, 2) + Math.pow(newZ, 2) Math.pow(newX, 2) + Math.pow(newZ, 2)
) )
...@@ -235,14 +249,14 @@ var FixedWingDroneAPI = /** @class */ (function () { ...@@ -235,14 +249,14 @@ var FixedWingDroneAPI = /** @class */ (function () {
verticalSpeed = this._computeVerticalSpeed( verticalSpeed = this._computeVerticalSpeed(
altitudeDiff, altitudeDiff,
this.getMaxClimbRate(), this.getMaxClimbRate(),
drone.getSpeed(), drone.getAirSpeed(),
this.getMaxPitchAngle() this.getMaxPitchAngle()
); );
} else { } else {
verticalSpeed = -this._computeVerticalSpeed( verticalSpeed = -this._computeVerticalSpeed(
Math.abs(altitudeDiff), Math.abs(altitudeDiff),
this.getMaxSinkRate(), this.getMaxSinkRate(),
drone.getSpeed(), drone.getAirSpeed(),
-this.getMinPitchAngle() -this.getMinPitchAngle()
); );
} }
...@@ -261,18 +275,14 @@ var FixedWingDroneAPI = /** @class */ (function () { ...@@ -261,18 +275,14 @@ var FixedWingDroneAPI = /** @class */ (function () {
drone.rotation.z + y); drone.rotation.z + y);
}; };
FixedWingDroneAPI.prototype.setAltitude = function (drone, altitude) {
drone._targetCoordinates.z = altitude;
};
FixedWingDroneAPI.prototype.setSpeed = function (drone, speed) { FixedWingDroneAPI.prototype.setSpeed = function (drone, speed) {
this._targetSpeed = Math.max( this._targetSpeed = Math.max(
Math.min(speed, this.getMaxSpeed()), Math.min(speed, this.getMaxSpeed()),
this.getMinSpeed() this.getMinSpeed()
); );
drone._acceleration = (this._targetSpeed > drone.getSpeed()) drone._acceleration = (this._targetSpeed > drone.getAirSpeed()) ?
? this.getMaxAcceleration() : -this.getMaxDeceleration(); this.getMaxAcceleration() : -this.getMaxDeceleration();
}; };
FixedWingDroneAPI.prototype.setStartingPosition = function (drone, x, y, z) { FixedWingDroneAPI.prototype.setStartingPosition = function (drone, x, y, z) {
...@@ -290,34 +300,18 @@ var FixedWingDroneAPI = /** @class */ (function () { ...@@ -290,34 +300,18 @@ var FixedWingDroneAPI = /** @class */ (function () {
this._drone_dict_list[id] = msg; this._drone_dict_list[id] = msg;
}; };
FixedWingDroneAPI.prototype.set_loiter_mode = function (radius) { FixedWingDroneAPI.prototype.internal_setTargetCoordinates =
function (drone, coordinates, radius) {
if (radius) {
this._loiter_mode = true; this._loiter_mode = true;
if (radius && radius > LOITER_LIMIT) { if (radius >= LOITER_LIMIT) {
this._loiter_radius = radius * LOITER_RADIUS_FACTOR; this._loiter_radius = radius;
this._loiter_center = this._last_target;
this._loiter_coordinates = [];
this._last_loiter_point_reached = -1;
var x1, y1, angle;
//for (var angle = 0; angle <360; angle+=8){ //counter-clockwise
for (angle = 360; angle > 0; angle -= 8) { //clockwise
x1 = this._loiter_radius *
Math.cos(this._toRad(angle)) + this._loiter_center.x;
y1 = this._loiter_radius *
Math.sin(this._toRad(angle)) + this._loiter_center.y;
this._loiter_coordinates.push(
this.getCurrentPosition(x1, y1, this._loiter_center.z)
);
}
} }
}; } else {
FixedWingDroneAPI.prototype.internal_setTargetCoordinates =
function (drone, coordinates, loiter) {
if (!loiter) {
this._loiter_mode = false; this._loiter_mode = false;
//save last target point to use as next loiter center
this._last_target = coordinates;
} }
}; };
FixedWingDroneAPI.prototype.sendMsg = function (msg, to) { FixedWingDroneAPI.prototype.sendMsg = function (msg, to) {
var _this = this, var _this = this,
droneList = _this._gameManager._droneList; droneList = _this._gameManager._droneList;
...@@ -362,79 +356,59 @@ var FixedWingDroneAPI = /** @class */ (function () { ...@@ -362,79 +356,59 @@ var FixedWingDroneAPI = /** @class */ (function () {
if (isNaN(lat) || isNaN(lon) || isNaN(z)) { if (isNaN(lat) || isNaN(lon) || isNaN(z)) {
throw new Error('Target coordinates must be numbers'); throw new Error('Target coordinates must be numbers');
} }
var x = this._mapManager.longitudToX(lon, this._map_dict.width), var point = this._mapManager.toLocalCoordinates(lat, lon,
y = this._mapManager.latitudeToY(lat, this._map_dict.depth), this._map_dict.map_size),
position = this._mapManager.normalize(x, y, this._map_dict), position = this._mapManager.normalize(point.x, point.y, this._map_dict);
processed_coordinates;
if (z > this._map_dict.start_AMSL) { if (z > this._map_dict.start_AMSL) {
z -= this._map_dict.start_AMSL; z -= this._map_dict.start_AMSL;
} }
processed_coordinates = { return {
x: position[0], x: position[0],
y: position[1], y: position[1],
z: z z: z
}; };
//this._last_altitude_point_reached = -1;
//this.takeoff_path = [];
return processed_coordinates;
}; };
FixedWingDroneAPI.prototype.getCurrentPosition = function (x, y, z) { FixedWingDroneAPI.prototype.getCurrentPosition = function (x, y, z) {
return this._mapManager.convertToGeoCoordinates(x, y, z, this._map_dict); return this._mapManager.convertToGeoCoordinates(x, y, z, this._map_dict);
}; };
FixedWingDroneAPI.prototype.loiter = function (drone) { FixedWingDroneAPI.prototype.getDroneViewInfo = function (drone) {
if (this._loiter_radius > LOITER_LIMIT) { var context = this, result = { "obstacles": [], "drones": [] }, distance,
var drone_pos = drone.getCurrentPosition(), other_position, drone_position = drone.getCurrentPosition();
min = 9999, function calculateDistance(a, b, _this) {
min_i, return _this._mapManager.latLonDistance([a.x, a.y], [b.x, b.y]);
i, }
d, context._gameManager._droneList.forEach(function (other) {
next_point; if (other.can_play && drone.id != other.id) {
//shift loiter circle to nearest point other_position = other.getCurrentPosition();
if (this._last_loiter_point_reached === -1) { distance = calculateDistance(drone_position, other_position, context);
if (!this.shifted) { if (distance <= VIEW_SCOPE) {
drone._maxSpeed = drone._maxSpeed * LOITER_SPEED_FACTOR; result.drones.push({
for (i = 0; i < this._loiter_coordinates.length; i += 1) { position: drone.getCurrentPosition(),
d = this._mapManager.latLonDistance([drone_pos.x, drone_pos.y], direction: drone.direction,
[this._loiter_coordinates[i].x, rotation: drone.rotation,
this._loiter_coordinates[i].y]); speed: drone.speed,
if (d < min) { team: drone.team
min = d; });
min_i = i;
}
}
this._loiter_coordinates = this._loiter_coordinates.concat(
this._loiter_coordinates.splice(0, min_i)
);
this.shifted = true;
}
} else {
this.shifted = false;
}
//stop
if (this._last_loiter_point_reached ===
this._loiter_coordinates.length - 1) {
if (drone._maxSpeed !== this.getMaxSpeed()) {
drone._maxSpeed = this.getMaxSpeed();
} }
drone.setDirection(0, 0, 0);
return;
} }
//loiter });
next_point = context._map_dict.geo_obstacle_list.forEach(function (obstacle) {
this._loiter_coordinates[this._last_loiter_point_reached + 1]; distance = calculateDistance(drone_position, obstacle.position, context);
this.internal_setTargetCoordinates(drone, next_point, true); if (distance <= VIEW_SCOPE) {
if (this._mapManager.latLonDistance([drone_pos.x, drone_pos.y], result.obstacles.push(obstacle);
[next_point.x, next_point.y]) < 1) {
this._last_loiter_point_reached += 1;
if (this._last_loiter_point_reached ===
this._loiter_coordinates.length - 1) {
return;
} }
next_point = this._loiter_coordinates[ });
this._last_loiter_point_reached + 1 if (drone.__is_getting_drone_view !== true) {
]; drone.__is_getting_drone_view = true;
this.internal_setTargetCoordinates(drone, next_point, true); context._gameManager.delay(function () {
drone.__is_getting_drone_view = false;
try {
drone.onDroneViewInfo(result);
} catch (error) {
console.warn('Drone crashed on drone view due to error:', error);
drone._internal_crash();
} }
}, 1000);
} }
}; };
FixedWingDroneAPI.prototype.getDroneAI = function () { FixedWingDroneAPI.prototype.getDroneAI = function () {
...@@ -475,9 +449,9 @@ var FixedWingDroneAPI = /** @class */ (function () { ...@@ -475,9 +449,9 @@ var FixedWingDroneAPI = /** @class */ (function () {
return Math.PI / 4; return Math.PI / 4;
}; };
FixedWingDroneAPI.prototype.getYawVelocity = function (drone) { FixedWingDroneAPI.prototype.getYawVelocity = function (drone) {
return 360 * EARTH_GRAVITY return 360 * EARTH_GRAVITY *
* Math.tan(this._toRad(this.getMaxRollAngle())) Math.tan(this._toRad(this.getMaxRollAngle())) /
/ (2 * Math.PI * drone.getSpeed()); (2 * Math.PI * drone.getAirSpeed());
}; };
FixedWingDroneAPI.prototype.getYaw = function (drone) { FixedWingDroneAPI.prototype.getYaw = function (drone) {
var direction = drone.worldDirection; var direction = drone.worldDirection;
...@@ -493,9 +467,10 @@ var FixedWingDroneAPI = /** @class */ (function () { ...@@ -493,9 +467,10 @@ var FixedWingDroneAPI = /** @class */ (function () {
}; };
FixedWingDroneAPI.prototype._computeVerticalSpeed = FixedWingDroneAPI.prototype._computeVerticalSpeed =
function (altitude_diff, max_climb_rate, speed, max_pitch) { function (altitude_diff, max_climb_rate, speed, max_pitch) {
var maxVerticalSpeed = Math.min(altitude_diff, Math.min(max_climb_rate, speed)); var maxVerticalSpeed =
return (this._toDeg(Math.asin(maxVerticalSpeed / speed)) > max_pitch) Math.min(altitude_diff, Math.min(max_climb_rate, speed));
? speed * Math.sin(this._toRad(max_pitch)) return (this._toDeg(Math.asin(maxVerticalSpeed / speed)) > max_pitch) ?
speed * Math.sin(this._toRad(max_pitch))
: maxVerticalSpeed; : maxVerticalSpeed;
}; };
FixedWingDroneAPI.prototype._toRad = function (angle) { FixedWingDroneAPI.prototype._toRad = function (angle) {
...@@ -505,13 +480,13 @@ var FixedWingDroneAPI = /** @class */ (function () { ...@@ -505,13 +480,13 @@ var FixedWingDroneAPI = /** @class */ (function () {
return angle * 180 / Math.PI; return angle * 180 / Math.PI;
}; };
FixedWingDroneAPI.prototype.getClimbRate = function (drone) { FixedWingDroneAPI.prototype.getClimbRate = function (drone) {
return drone.worldDirection.y * drone.getSpeed(); return drone.worldDirection.y * drone.getAirSpeed();
}; };
FixedWingDroneAPI.prototype.getGroundSpeed = function (drone) { FixedWingDroneAPI.prototype.getGroundSpeed = function (drone) {
var direction = drone.worldDirection; var direction = drone.worldDirection;
return Math.sqrt( return Math.sqrt(
Math.pow(direction.x * drone.getSpeed(), 2) Math.pow(direction.x * drone.getAirSpeed(), 2) +
+ Math.pow(direction.z * drone.getSpeed(), 2) Math.pow(direction.z * drone.getAirSpeed(), 2)
); );
}; };
FixedWingDroneAPI.prototype.triggerParachute = function (drone) { FixedWingDroneAPI.prototype.triggerParachute = function (drone) {
...@@ -526,10 +501,10 @@ var FixedWingDroneAPI = /** @class */ (function () { ...@@ -526,10 +501,10 @@ var FixedWingDroneAPI = /** @class */ (function () {
return; return;
}; };
FixedWingDroneAPI.prototype.getInitialAltitude = function () { FixedWingDroneAPI.prototype.getInitialAltitude = function () {
return 0; return this._map_dict.start_AMSL;
}; };
FixedWingDroneAPI.prototype.getAltitudeAbs = function (altitude) { FixedWingDroneAPI.prototype.getAltitudeAbs = function (altitude) {
return altitude; return altitude + this._map_dict.start_AMSL;
}; };
FixedWingDroneAPI.prototype.getMinHeight = function () { FixedWingDroneAPI.prototype.getMinHeight = function () {
return 0; return 0;
......
...@@ -246,7 +246,7 @@ ...@@ -246,7 +246,7 @@
</item> </item>
<item> <item>
<key> <string>serial</string> </key> <key> <string>serial</string> </key>
<value> <string>1007.63305.59225.51968</string> </value> <value> <string>1010.5034.64121.33006</string> </value>
</item> </item>
<item> <item>
<key> <string>state</string> </key> <key> <string>state</string> </key>
...@@ -266,7 +266,7 @@ ...@@ -266,7 +266,7 @@
</tuple> </tuple>
<state> <state>
<tuple> <tuple>
<float>1682437182.61</float> <float>1690565260.64</float>
<string>UTC</string> <string>UTC</string>
</tuple> </tuple>
</state> </state>
......
/*global BABYLON, RSVP, console, FixedWingDroneAPI, document*/ /*global BABYLON, RSVP, console, FixedWingDroneAPI, EnemyDroneAPI, document*/
/*jslint nomen: true, indent: 2, maxlen: 80, todo: true, /*jslint nomen: true, indent: 2, maxlen: 80, todo: true,
unparam: true */ unparam: true */
var GAMEPARAMETERS = {}; var GAMEPARAMETERS = {}, TEAM_USER = "user", TEAM_ENEMY = "enemy";
//for DEBUG/TEST mode
var baseLogFunction = console.log, console_log = "";
/******************************* DRONE MANAGER ********************************/ /******************************* DRONE MANAGER ********************************/
var DroneManager = /** @class */ (function () { var DroneManager = /** @class */ (function () {
"use strict"; "use strict";
//** CONSTRUCTOR //** CONSTRUCTOR
function DroneManager(scene, id, API) { function DroneManager(scene, id, API, team) {
this._mesh = null; this._mesh = null;
this._controlMesh = null; this._controlMesh = null;
this._canPlay = false; this._canPlay = false;
...@@ -31,8 +33,9 @@ var DroneManager = /** @class */ (function () { ...@@ -31,8 +33,9 @@ var DroneManager = /** @class */ (function () {
this._scene = scene; this._scene = scene;
this._canUpdate = true; this._canUpdate = true;
this._id = id; this._id = id;
this._leader_id = 0; this._team = team;
this._API = API; // var API created on AI evel this._API = API; // var API created on AI evel
this._score = 0;
// Create the control mesh // Create the control mesh
this._controlMesh = BABYLON.Mesh.CreateBox( this._controlMesh = BABYLON.Mesh.CreateBox(
"droneControl_" + id, "droneControl_" + id,
...@@ -61,11 +64,6 @@ var DroneManager = /** @class */ (function () { ...@@ -61,11 +64,6 @@ var DroneManager = /** @class */ (function () {
// swap y and z axis so z axis represents altitude // swap y and z axis so z axis represents altitude
return new BABYLON.Vector3(vector.x, vector.z, vector.y); return new BABYLON.Vector3(vector.x, vector.z, vector.y);
}; };
Object.defineProperty(DroneManager.prototype, "leader_id", {
get: function () { return this._leader_id; },
enumerable: true,
configurable: true
});
Object.defineProperty(DroneManager.prototype, "drone_dict", { Object.defineProperty(DroneManager.prototype, "drone_dict", {
get: function () { return this._API._drone_dict_list; }, get: function () { return this._API._drone_dict_list; },
enumerable: true, enumerable: true,
...@@ -73,6 +71,7 @@ var DroneManager = /** @class */ (function () { ...@@ -73,6 +71,7 @@ var DroneManager = /** @class */ (function () {
}); });
Object.defineProperty(DroneManager.prototype, "can_play", { Object.defineProperty(DroneManager.prototype, "can_play", {
get: function () { return this._canPlay; }, get: function () { return this._canPlay; },
set: function (value) { this._canPlay = value; },
enumerable: true, enumerable: true,
configurable: true configurable: true
}); });
...@@ -81,6 +80,17 @@ var DroneManager = /** @class */ (function () { ...@@ -81,6 +80,17 @@ var DroneManager = /** @class */ (function () {
enumerable: true, enumerable: true,
configurable: true configurable: true
}); });
Object.defineProperty(DroneManager.prototype, "score", {
get: function () { return this._score; },
set: function (value) { this._score = value; },
enumerable: true,
configurable: true
});
Object.defineProperty(DroneManager.prototype, "team", {
get: function () { return this._team; },
enumerable: true,
configurable: true
});
Object.defineProperty(DroneManager.prototype, "colliderMesh", { Object.defineProperty(DroneManager.prototype, "colliderMesh", {
get: function () { return this._mesh; }, get: function () { return this._mesh; },
enumerable: true, enumerable: true,
...@@ -124,11 +134,10 @@ var DroneManager = /** @class */ (function () { ...@@ -124,11 +134,10 @@ var DroneManager = /** @class */ (function () {
enumerable: true, enumerable: true,
configurable: true configurable: true
}); });
DroneManager.prototype.internal_start = function (initial_position) { DroneManager.prototype.internal_start = function () {
this._API.internal_start(this); this._API.internal_start(this);
this._canPlay = true; this._canPlay = true;
this._canCommunicate = true; this._canCommunicate = true;
this._targetCoordinates = initial_position;
try { try {
return this.onStart(); return this.onStart();
} catch (error) { } catch (error) {
...@@ -140,6 +149,10 @@ var DroneManager = /** @class */ (function () { ...@@ -140,6 +149,10 @@ var DroneManager = /** @class */ (function () {
* Set a target point to move * Set a target point to move
*/ */
DroneManager.prototype.setTargetCoordinates = function (x, y, z) { DroneManager.prototype.setTargetCoordinates = function (x, y, z) {
this._internal_setTargetCoordinates(x, y, z);
};
DroneManager.prototype._internal_setTargetCoordinates =
function (x, y, z, radius) {
if (!this._canPlay) { if (!this._canPlay) {
return; return;
} }
...@@ -147,9 +160,20 @@ var DroneManager = /** @class */ (function () { ...@@ -147,9 +160,20 @@ var DroneManager = /** @class */ (function () {
this._targetCoordinates = this._API.processCoordinates(x, y, z); this._targetCoordinates = this._API.processCoordinates(x, y, z);
return this._API.internal_setTargetCoordinates( return this._API.internal_setTargetCoordinates(
this, this,
this._targetCoordinates this._targetCoordinates,
radius
); );
}; };
/**
* Returns the list of things a drone "sees"
*/
DroneManager.prototype.getDroneViewInfo = function () {
var context = this;
if (this._controlMesh) {
return context._API.getDroneViewInfo(context);
}
return;
};
DroneManager.prototype.internal_update = function (delta_time) { DroneManager.prototype.internal_update = function (delta_time) {
var context = this; var context = this;
if (this._controlMesh) { if (this._controlMesh) {
...@@ -194,7 +218,7 @@ var DroneManager = /** @class */ (function () { ...@@ -194,7 +218,7 @@ var DroneManager = /** @class */ (function () {
} }
return this._API.setStartingPosition(this, x, y, z); return this._API.setStartingPosition(this, x, y, z);
}; };
DroneManager.prototype.setSpeed = function (speed) { DroneManager.prototype.setAirSpeed = function (speed) {
if (!this._canPlay) { if (!this._canPlay) {
return; return;
} }
...@@ -292,20 +316,11 @@ var DroneManager = /** @class */ (function () { ...@@ -292,20 +316,11 @@ var DroneManager = /** @class */ (function () {
} }
return null; return null;
}; };
DroneManager.prototype.setAltitude = function (altitude) {
if (!this._canPlay) {
return;
}
return this._API.setAltitude(this, altitude);
};
/** /**
* Make the drone loiter (circle with a set radius) * Make the drone loiter (circle with a set radius)
*/ */
DroneManager.prototype.loiter = function (radius) { DroneManager.prototype.loiter = function (x, y, z, radius) {
if (!this._canPlay) { this._internal_setTargetCoordinates(x, y, z, radius);
return;
}
this._API.set_loiter_mode(radius);
}; };
DroneManager.prototype.getFlightParameters = function () { DroneManager.prototype.getFlightParameters = function () {
if (this._API.getFlightParameters) { if (this._API.getFlightParameters) {
...@@ -314,19 +329,31 @@ var DroneManager = /** @class */ (function () { ...@@ -314,19 +329,31 @@ var DroneManager = /** @class */ (function () {
return null; return null;
}; };
DroneManager.prototype.getYaw = function () { DroneManager.prototype.getYaw = function () {
if (typeof this._API.getYaw !== "undefined") {
return this._API.getYaw(this); return this._API.getYaw(this);
}
return;
}; };
DroneManager.prototype.getSpeed = function () { DroneManager.prototype.getAirSpeed = function () {
return this._speed; return this._speed;
}; };
DroneManager.prototype.getGroundSpeed = function () { DroneManager.prototype.getGroundSpeed = function () {
if (typeof this._API.getGroundSpeed !== "undefined") {
return this._API.getGroundSpeed(this); return this._API.getGroundSpeed(this);
}
return;
}; };
DroneManager.prototype.getClimbRate = function () { DroneManager.prototype.getClimbRate = function () {
if (typeof this._API.getClimbRate !== "undefined") {
return this._API.getClimbRate(this); return this._API.getClimbRate(this);
}
return;
}; };
DroneManager.prototype.getSinkRate = function () { DroneManager.prototype.getSinkRate = function () {
return this._API.getSinkRate(); if (typeof this._API.getSinkRate !== "undefined") {
return this._API.getSinkRate(this);
}
return;
}; };
DroneManager.prototype.triggerParachute = function () { DroneManager.prototype.triggerParachute = function () {
return this._API.triggerParachute(this); return this._API.triggerParachute(this);
...@@ -364,6 +391,12 @@ var DroneManager = /** @class */ (function () { ...@@ -364,6 +391,12 @@ var DroneManager = /** @class */ (function () {
* @param msg The message * @param msg The message
*/ */
DroneManager.prototype.onGetMsg = function () { return; }; DroneManager.prototype.onGetMsg = function () { return; };
/**
* Function called when drone finished processing drone view
* (as result of getDroneViewInfo call)
*/
DroneManager.prototype.onDroneViewInfo = function (drone_view) { return; };
return DroneManager; return DroneManager;
}()); }());
...@@ -375,41 +408,70 @@ var DroneManager = /** @class */ (function () { ...@@ -375,41 +408,70 @@ var DroneManager = /** @class */ (function () {
var MapManager = /** @class */ (function () { var MapManager = /** @class */ (function () {
"use strict"; "use strict";
function calculateMapInfo(map, map_dict, initial_position) { //random geo-point:
var max_width = map.latLonDistance([map_dict.min_lat, map_dict.min_lon], var MIN_LAT = 45.64,
[map_dict.min_lat, map_dict.max_lon]), MIN_LON = 14.253,
max_height = map.latLonDistance([map_dict.min_lat, map_dict.min_lon], EPSILON = 9.9,
[map_dict.max_lat, map_dict.min_lon]), START_Z = 15,
map_size = Math.ceil(Math.max(max_width, max_height)) * 0.6, R = 6371e3;
map_info = { function calculateMapInfo(map, map_dict) {
"depth": map_size, var min_lat = map_dict.min_lat || MIN_LAT,
min_lon = map_dict.min_lon || MIN_LON,
offset = map.latLonOffset(min_lat, min_lon, map_dict.map_size),
max_lat = offset[0],
max_lon = offset[1],
starting_point = map_dict.map_size / 2 * -0.75,
local_min = map.toLocalCoordinates(min_lat, min_lon, map_dict.map_size),
local_max = map.toLocalCoordinates(max_lat, max_lon, map_dict.map_size);
map.map_info = {
"depth": map_dict.map_size,
"width": map_dict.map_size,
"map_size": map_dict.map_size,
"min_lat": min_lat,
"min_lon": min_lon,
"max_lat": max_lat,
"max_lon": max_lon,
"min_x": local_min.x,
"min_y": local_min.y,
"max_x": local_max.x,
"max_y": local_max.y,
"height": map_dict.height, "height": map_dict.height,
"width": map_size, "start_AMSL": map_dict.start_AMSL,
"map_size": map_size, "flag_list": map_dict.flag_list,
"min_x": map.longitudToX(map_dict.min_lon, map_size), "geo_flag_list": [],
"min_y": map.latitudeToY(map_dict.min_lat, map_size), "flag_distance_epsilon": map_dict.flag_distance_epsilon || EPSILON,
"max_x": map.longitudToX(map_dict.max_lon, map_size), "obstacle_list": map_dict.obstacle_list,
"max_y": map.latitudeToY(map_dict.max_lat, map_size), "geo_obstacle_list": [],
"start_AMSL": map_dict.start_AMSL "initial_position": {
}, "x": 0,
position = map.normalize( "y": starting_point,
map.longitudToX(initial_position.longitude, map_size), "z": START_Z
map.latitudeToY(initial_position.latitude, map_size), }
map_info
);
map_info.initial_position = {
"x": position[0],
"y": position[1],
"z": initial_position.z
}; };
return map_info; map_dict.flag_list.forEach(function (flag_info, index) {
map.map_info.geo_flag_list.push(map.convertToGeoCoordinates(
flag_info.position.x,
flag_info.position.y,
flag_info.position.z
));
});
map_dict.obstacle_list.forEach(function (obstacle_info, index) {
var geo_obstacle = {};
Object.assign(geo_obstacle, obstacle_info);
geo_obstacle.position = map.convertToGeoCoordinates(
obstacle_info.position.x,
obstacle_info.position.y,
obstacle_info.position.z
);
map.map_info.geo_obstacle_list.push(geo_obstacle);
});
} }
//** CONSTRUCTOR //** CONSTRUCTOR
function MapManager(scene) { function MapManager(scene) {
var _this = this, max_sky, skybox, skyboxMat, largeGroundMat, var _this = this, max_sky, skybox, skyboxMat, largeGroundMat, flag_material,
largeGroundBottom, width, depth, terrain, max; largeGroundBottom, width, depth, terrain, max, flag_a, flag_b, mast, flag,
_this.map_info = calculateMapInfo(_this, GAMEPARAMETERS.map, count = 0, new_obstacle;
GAMEPARAMETERS.initialPosition); calculateMapInfo(_this, GAMEPARAMETERS.map);
max = _this.map_info.width; max = _this.map_info.width;
if (_this.map_info.depth > max) { if (_this.map_info.depth > max) {
max = _this.map_info.depth; max = _this.map_info.depth;
...@@ -419,18 +481,18 @@ var MapManager = /** @class */ (function () { ...@@ -419,18 +481,18 @@ var MapManager = /** @class */ (function () {
} }
max = max < _this.map_info.depth ? _this.map_info.depth : max; max = max < _this.map_info.depth ? _this.map_info.depth : max;
// Skybox // Skybox
max_sky = (max * 10 < 20000) ? max * 10 : 20000; max_sky = (max * 15 < 20000) ? max * 15 : 20000; //skybox scene limit
skybox = BABYLON.Mesh.CreateBox("skyBox", max_sky, scene); skybox = BABYLON.MeshBuilder.CreateBox("skyBox", { size: max_sky }, scene);
skybox.infiniteDistance = true;
skybox.renderingGroupId = 0;
skyboxMat = new BABYLON.StandardMaterial("skybox", scene); skyboxMat = new BABYLON.StandardMaterial("skybox", scene);
skyboxMat.backFaceCulling = false; skyboxMat.backFaceCulling = false;
skyboxMat.disableLighting = true; skyboxMat.disableLighting = true;
skybox.material = skyboxMat;
skybox.infiniteDistance = true;
skyboxMat.disableLighting = true;
skyboxMat.reflectionTexture = new BABYLON.CubeTexture("./assets/skybox/sky", skyboxMat.reflectionTexture = new BABYLON.CubeTexture("./assets/skybox/sky",
scene); scene);
skyboxMat.reflectionTexture.coordinatesMode = BABYLON.Texture.SKYBOX_MODE; skyboxMat.reflectionTexture.coordinatesMode = BABYLON.Texture.SKYBOX_MODE;
skyboxMat.infiniteDistance = true; skybox.renderingGroupId = 0;
skybox.material = skyboxMat;
// Plane from bottom // Plane from bottom
largeGroundMat = new BABYLON.StandardMaterial("largeGroundMat", scene); largeGroundMat = new BABYLON.StandardMaterial("largeGroundMat", scene);
largeGroundMat.specularColor = BABYLON.Color3.Black(); largeGroundMat.specularColor = BABYLON.Color3.Black();
...@@ -441,8 +503,7 @@ var MapManager = /** @class */ (function () { ...@@ -441,8 +503,7 @@ var MapManager = /** @class */ (function () {
largeGroundBottom.rotation.x = -Math.PI / 2; largeGroundBottom.rotation.x = -Math.PI / 2;
largeGroundBottom.rotation.y = Math.PI; largeGroundBottom.rotation.y = Math.PI;
largeGroundBottom.material = largeGroundMat; largeGroundBottom.material = largeGroundMat;
// Camera largeGroundBottom.renderingGroupId = 1;
scene.activeCamera.upperRadiusLimit = max * 4;
// Terrain // Terrain
// Give map some margin from the flight limits // Give map some margin from the flight limits
width = _this.map_info.width * 1.10; width = _this.map_info.width * 1.10;
...@@ -453,19 +514,122 @@ var MapManager = /** @class */ (function () { ...@@ -453,19 +514,122 @@ var MapManager = /** @class */ (function () {
terrain.position = BABYLON.Vector3.Zero(); terrain.position = BABYLON.Vector3.Zero();
terrain.scaling = new BABYLON.Vector3(depth / 50000, depth / 50000, terrain.scaling = new BABYLON.Vector3(depth / 50000, depth / 50000,
width / 50000); width / 50000);
// Obstacles
_this._obstacle_list = [];
_this.map_info.obstacle_list.forEach(function (obstacle) {
switch (obstacle.type) {
case "box":
new_obstacle = BABYLON.MeshBuilder.CreateBox("obs_" + count,
{ 'size': 1 }, scene);
break;
case "cylinder":
new_obstacle = BABYLON.MeshBuilder.CreateCylinder("obs_" + count, {
'diameterBottom': obstacle.diameterBottom,
'diameterTop': obstacle.diameterTop,
'height': 1
}, scene);
break;
case "sphere":
new_obstacle = BABYLON.MeshBuilder.CreateSphere("obs_" + count, {
'diameterX': obstacle.scale.x,
'diameterY': obstacle.scale.z,
'diameterZ': obstacle.scale.y
}, scene);
break;
default:
return;
}
new_obstacle.type = obstacle.type;
var convertion = Math.PI / 180;
if ("position" in obstacle)
new_obstacle.position = new BABYLON.Vector3(obstacle.position.x,
obstacle.position.z,
obstacle.position.y);
if ("rotation" in obstacle)
new_obstacle.rotation =
new BABYLON.Vector3(obstacle.rotation.x * convertion,
obstacle.rotation.z * convertion,
obstacle.rotation.y * convertion);
if ("scale" in obstacle)
new_obstacle.scaling = new BABYLON.Vector3(obstacle.scale.x,
obstacle.scale.z,
obstacle.scale.y);
var obs_material = new BABYLON.StandardMaterial("obsmat_" + count, scene);
obs_material.alpha = 1;
obs_material.diffuseColor = new BABYLON.Color3(255, 153, 0);
new_obstacle.material = obs_material;
_this._obstacle_list.push(new_obstacle);
count++;
});
// Flags
_this._flag_list = [];
var FLAG_SIZE = {
'x': 1,
'y': 1,
'z': 6
};
_this.map_info.flag_list.forEach(function (flag_info, index) {
flag_material = new BABYLON.StandardMaterial("flag_mat_" + index, scene);
flag_material.alpha = 1;
flag_material.diffuseColor = BABYLON.Color3.Green();
flag_a = BABYLON.MeshBuilder.CreateDisc("flag_a_" + index,
{radius: 7, tessellation: 3},
scene);
flag_a.material = flag_material;
flag_a.position = new BABYLON.Vector3(
flag_info.position.x + 1,
FLAG_SIZE.z + 1, //swap
flag_info.position.y - 1
);
flag_a.rotation = new BABYLON.Vector3(0, 1, 0);
flag_b = BABYLON.MeshBuilder.CreateDisc("flag_b_" + index,
{radius: 3, tessellation: 3},
scene);
flag_b.material = flag_material;
flag_b.position = new BABYLON.Vector3(
flag_info.position.x - 1,
FLAG_SIZE.z + 1, //swap
flag_info.position.y + 1
);
flag_b.rotation = new BABYLON.Vector3(0, 4, 0);
mast = BABYLON.MeshBuilder.CreateBox("mast_" + index,
{ 'size': 1 }, scene);
mast.position = new BABYLON.Vector3(
flag_info.position.x,
FLAG_SIZE.z / 2, //swap
flag_info.position.y
);
mast.scaling = new BABYLON.Vector3(
FLAG_SIZE.x,
FLAG_SIZE.z, //swap
FLAG_SIZE.y);
mast.material = flag_material;
flag = BABYLON.Mesh.MergeMeshes([flag_a, flag_b, mast]);
flag.id = index;
//flag.weight = _this.map_info.flag_weight;
flag.location = flag_info.position;
flag.drone_collider_list = [];
_this._flag_list.push(flag);
});
} }
MapManager.prototype.getMapInfo = function () { MapManager.prototype.getMapInfo = function () {
return this.map_info; return this.map_info;
}; };
MapManager.prototype.longitudToX = function (lon, map_size) { MapManager.prototype.latLonOffset = function (lat, lon, offset_in_mt) {
return (map_size / 360.0) * (180 + lon); var R = 6371e3, //Earth radius
lat_offset = offset_in_mt / R,
lon_offset = offset_in_mt / (R * Math.cos(Math.PI * lat / 180));
return [lat + lat_offset * 180 / Math.PI,
lon + lon_offset * 180 / Math.PI];
};
MapManager.prototype.toLocalCoordinates = function (lat, lon, map_size) {
return {
"x": (map_size / 360.0) * (180 + lon),
"y": (map_size / 180.0) * (90 - lat)
}; };
MapManager.prototype.latitudeToY = function (lat, map_size) {
return (map_size / 180.0) * (90 - lat);
}; };
MapManager.prototype.latLonDistance = function (c1, c2) { MapManager.prototype.latLonDistance = function (c1, c2) {
var R = 6371e3, var q1 = c1[0] * Math.PI / 180,
q1 = c1[0] * Math.PI / 180,
q2 = c2[0] * Math.PI / 180, q2 = c2[0] * Math.PI / 180,
dq = (c2[0] - c1[0]) * Math.PI / 180, dq = (c2[0] - c1[0]) * Math.PI / 180,
dl = (c2[1] - c1[1]) * Math.PI / 180, dl = (c2[1] - c1[1]) * Math.PI / 180,
...@@ -481,8 +645,9 @@ var MapManager = /** @class */ (function () { ...@@ -481,8 +645,9 @@ var MapManager = /** @class */ (function () {
return [n_x * 1000 - map_dict.width / 2, return [n_x * 1000 - map_dict.width / 2,
n_y * 1000 - map_dict.depth / 2]; n_y * 1000 - map_dict.depth / 2];
}; };
MapManager.prototype.convertToGeoCoordinates = function (x, y, z, map_dict) { MapManager.prototype.convertToGeoCoordinates = function (x, y, z) {
var lon = x + map_dict.width / 2, var map_dict = this.map_info,
lon = x + map_dict.width / 2,
lat = y + map_dict.depth / 2; lat = y + map_dict.depth / 2;
lon = lon / 1000; lon = lon / 1000;
lon = lon * (map_dict.max_x - map_dict.min_x) + lon = lon * (map_dict.max_x - map_dict.min_x) +
...@@ -511,11 +676,15 @@ var GameManager = /** @class */ (function () { ...@@ -511,11 +676,15 @@ var GameManager = /** @class */ (function () {
"use strict"; "use strict";
// *** CONSTRUCTOR *** // *** CONSTRUCTOR ***
function GameManager(canvas, game_parameters_json) { function GameManager(canvas, game_parameters_json) {
var drone, header_list; var drone, header_list, drone_count;
this._canvas = canvas; this._canvas = canvas;
this._canvas_width = canvas.width;
this._canvas_height = canvas.height;
this._scene = null; this._scene = null;
this._engine = null; this._engine = null;
this._droneList = []; this._droneList = [];
this._droneList_user = [];
this._droneList_enemy = [];
this._canUpdate = false; this._canUpdate = false;
this._max_step_animation_frame = game_parameters_json.simulation_speed; this._max_step_animation_frame = game_parameters_json.simulation_speed;
if (!this._max_step_animation_frame) { this._max_step_animation_frame = 5; } if (!this._max_step_animation_frame) { this._max_step_animation_frame = 5; }
...@@ -524,19 +693,25 @@ var GameManager = /** @class */ (function () { ...@@ -524,19 +693,25 @@ var GameManager = /** @class */ (function () {
this._map_swapped = false; this._map_swapped = false;
this._log_count = []; this._log_count = [];
this._flight_log = []; this._flight_log = [];
if (GAMEPARAMETERS.draw_flight_path) { this._result_message = "";
this._last_position_drawn = []; if (GAMEPARAMETERS.log_drone_flight) {
this._trace_objects_per_drone = [];
// ! Be aware that the following functions relies on this log format: // ! Be aware that the following functions relies on this log format:
// - getLogEntries at Drone Simulator Log Page // - getLogEntries at Drone Simulator Log Page
// - getLogEntries at Dron Log Follower API // - getLogEntries at Drone Log Follower API
header_list = ["timestamp (ms)", "latitude (°)", "longitude (°)", header_list = ["timestamp (ms)", "latitude (°)", "longitude (°)",
"AMSL (m)", "rel altitude (m)", "yaw (°)", "AMSL (m)", "rel altitude (m)", "yaw (°)",
"ground speed (m/s)", "climb rate (m/s)"]; "ground speed (m/s)", "climb rate (m/s)"];
for (drone = 0; drone < GAMEPARAMETERS.droneList.length; drone += 1) { drone_count = GAMEPARAMETERS.map.drones.user.length +
GAMEPARAMETERS.map.drones.enemy.length;
for (drone = 0; drone < drone_count; drone += 1) {
this._flight_log[drone] = []; this._flight_log[drone] = [];
this._flight_log[drone].push(header_list); this._flight_log[drone].push(header_list);
this._log_count[drone] = 0; this._log_count[drone] = 0;
}
if (GAMEPARAMETERS.draw_flight_path) {
this._last_position_drawn = [];
this._trace_objects_per_drone = [];
for (drone = 0; drone < drone_count; drone += 1) {
this._last_position_drawn[drone] = null; this._last_position_drawn[drone] = null;
this._trace_objects_per_drone[drone] = []; this._trace_objects_per_drone[drone] = [];
} }
...@@ -553,10 +728,20 @@ var GameManager = /** @class */ (function () { ...@@ -553,10 +728,20 @@ var GameManager = /** @class */ (function () {
new BABYLON.Color3(0, 0, 128) new BABYLON.Color3(0, 0, 128)
]; ];
} }
}
this.APIs_dict = { this.APIs_dict = {
FixedWingDroneAPI: FixedWingDroneAPI/*, FixedWingDroneAPI: FixedWingDroneAPI,
DroneLogAPI: DroneLogAPI*/ EnemyDroneAPI: EnemyDroneAPI
}; };
if (this._game_parameters_json.debug_test_mode) {
console.log = function () {
baseLogFunction.apply(console, arguments);
var args = Array.prototype.slice.call(arguments);
for (var i = 0;i < args.length;i++) {
console_log += args[i] + "\n";
}
};
}
} }
Object.defineProperty(GameManager.prototype, "gameParameter", { Object.defineProperty(GameManager.prototype, "gameParameter", {
...@@ -571,11 +756,15 @@ var GameManager = /** @class */ (function () { ...@@ -571,11 +756,15 @@ var GameManager = /** @class */ (function () {
var gadget = this; var gadget = this;
return gadget._init() return gadget._init()
.push(function () { .push(function () {
return gadget._flight_log; return {
'message': gadget._result_message,
'content': gadget._flight_log,
'console_log': console_log
};
}); });
}; };
GameManager.prototype.update = function () { GameManager.prototype.update = function (fullscreen) {
// time delta means that drone are updated every virtual second // time delta means that drone are updated every virtual second
// This is fixed and must not be modified // This is fixed and must not be modified
// otherwise, it will lead to different scenario results // otherwise, it will lead to different scenario results
...@@ -587,10 +776,8 @@ var GameManager = /** @class */ (function () { ...@@ -587,10 +776,8 @@ var GameManager = /** @class */ (function () {
function triggerUpdateIfPossible() { function triggerUpdateIfPossible() {
if ((_this._canUpdate) && (_this.ongoing_update_promise === null) && if ((_this._canUpdate) && (_this.ongoing_update_promise === null) &&
(0 < _this.waiting_update_count)) { (0 < _this.waiting_update_count)) {
_this.ongoing_update_promise = _this._update( _this.ongoing_update_promise = _this._update(TIME_DELTA, fullscreen)
TIME_DELTA, .push(function () {
(_this.waiting_update_count === 1)
).push(function () {
_this.waiting_update_count -= 1; _this.waiting_update_count -= 1;
_this.ongoing_update_promise = null; _this.ongoing_update_promise = null;
triggerUpdateIfPossible(); triggerUpdateIfPossible();
...@@ -617,16 +804,98 @@ var GameManager = /** @class */ (function () { ...@@ -617,16 +804,98 @@ var GameManager = /** @class */ (function () {
this._flight_log[drone._id].push(error.stack); this._flight_log[drone._id].push(error.stack);
}; };
GameManager.prototype._checkDroneRules = function (drone) { GameManager.prototype._checkDroneOut = function (drone) {
//TODO move this to API methods. if (drone.position) {
//each type of drone should define its rules var map_limit = this._mapManager.getMapInfo().map_size / 2;
if (drone.getCurrentPosition()) { return (drone.position.z > this._mapManager.getMapInfo().height) ||
return drone.getCurrentPosition().z > 1; (drone.position.x < -map_limit) ||
(drone.position.x > map_limit) ||
(drone.position.y < -map_limit) ||
(drone.position.y > map_limit);
}
};
GameManager.prototype._checkObstacleCollision = function (drone, obstacle) {
var closest = void 0, projected = BABYLON.Vector3.Zero();
if (drone.colliderMesh &&
drone.colliderMesh.intersectsMesh(obstacle, true)) {
drone._internal_crash(new Error('Drone ' + drone.id +
' touched an obstacle.'));
//Following workaround seems not needed with new babylonjs versions
/**
* Closest facet check is needed for sphere and cylinder,
* but just seemed bugged with the box
* So only need to check intersectMesh for the box
*/
/*if (obstacle.type == "box") {
closest = true;
} else {
obstacle.updateFacetData();
closest = obstacle.getClosestFacetAtCoordinates(
drone.infosMesh.position.x,
drone.infosMesh.position.y,
drone.infosMesh.position.z, projected);
}
if (closest !== null) {
drone._internal_crash(new Error('Drone ' + drone.id +
' touched an obstacle.'));
}*/
} }
return false;
}; };
GameManager.prototype._update = function (delta_time) { GameManager.prototype._checkFlagCollision = function (drone, flag) {
if (drone.team == TEAM_ENEMY) return;
function distance(a, b) {
return Math.sqrt(Math.pow((a.x - b.x), 2) + Math.pow((a.y - b.y), 2) +
Math.pow((a.z - b.z), 2));
}
if (drone.position) {
//TODO epsilon distance is 15 because of fixed wing loiter flights
//there is not a proper collision
if (distance(drone.position, flag.location) <=
this._mapManager.getMapInfo().flag_distance_epsilon) {
if (!flag.drone_collider_list.includes(drone.id)) {
//TODO notify the drone somehow? Or the AI script is in charge?
//console.log("flag " + flag.id + " hit by drone " + drone.id);
drone._internal_crash(new Error('Drone ' + drone.id +
' touched a flag.'));
if (flag.drone_collider_list.length === 0) {
drone.score++;
flag.drone_collider_list.push(drone.id);
}
}
}
}
};
GameManager.prototype._checkCollision = function (drone, other) {
if (drone.colliderMesh && other.colliderMesh &&
drone.colliderMesh.intersectsMesh(other.colliderMesh, false)) {
var angle = Math.acos(BABYLON.Vector3.Dot(drone.worldDirection,
other.worldDirection) /
(drone.worldDirection.length() *
other.worldDirection.length()));
//TODO is this parameter set? keep it or make 2 drones die when intersect?
if (angle < GAMEPARAMETERS.drone.collisionSector) {
if (drone.speed > other.speed) {
other._internal_crash(new Error('Drone ' + drone.id +
' bump drone ' + other.id + '.'));
}
else {
drone._internal_crash(new Error('Drone ' + other.id +
' bumped drone ' + drone.id + '.'));
}
}
else {
drone._internal_crash(new Error('Drone ' + drone.id +
' touched drone ' + other.id + '.'));
other._internal_crash(new Error('Drone ' + drone.id +
' touched drone ' + other.id + '.'));
}
}
};
GameManager.prototype._update = function (delta_time, fullscreen) {
var _this = this, var _this = this,
queue = new RSVP.Queue(), queue = new RSVP.Queue(),
i; i;
...@@ -642,14 +911,48 @@ var GameManager = /** @class */ (function () { ...@@ -642,14 +911,48 @@ var GameManager = /** @class */ (function () {
} }
} }
if (fullscreen) {
//Only resize if size changes
if (this._canvas.width !== GAMEPARAMETERS.fullscreen.width) {
this._canvas.width = GAMEPARAMETERS.fullscreen.width;
this._canvas.height = GAMEPARAMETERS.fullscreen.height;
}
} else {
if (this._canvas.width !== this._canvas_width) {
this._canvas.width = this._canvas_width;
this._canvas.height = this._canvas_height;
this._engine.resize(true);
}
}
this._droneList.forEach(function (drone) { this._droneList.forEach(function (drone) {
queue.push(function () { queue.push(function () {
var msg = '';
drone._tick += 1; drone._tick += 1;
if (_this._checkDroneRules(drone)) { if (drone.can_play) {
return drone.internal_update(delta_time); if (drone.getCurrentPosition().z <= 0) {
drone._internal_crash(new Error('Drone ' + drone.id +
' touched the floor.'));
}
else if (_this._checkDroneOut(drone)) {
drone._internal_crash(new Error('Drone ' + drone.id +
' out of limits.'));
}
else {
_this._droneList.forEach(function (other) {
if (other.can_play && drone.id != other.id) {
_this._checkCollision(drone, other);
}
});
_this._mapManager._obstacle_list.forEach(function (obstacle) {
_this._checkObstacleCollision(drone, obstacle);
});
_this._mapManager._flag_list.forEach(function (flag) {
_this._checkFlagCollision(drone, flag);
});
}
} }
//TODO error must be defined by the api? return drone.internal_update(delta_time);
drone._internal_crash('Drone touched the floor');
}); });
}); });
...@@ -657,10 +960,17 @@ var GameManager = /** @class */ (function () { ...@@ -657,10 +960,17 @@ var GameManager = /** @class */ (function () {
.push(function () { .push(function () {
if (_this._timeOut()) { if (_this._timeOut()) {
console.log("TIMEOUT!"); console.log("TIMEOUT!");
_this._result_message += "TIMEOUT!";
return _this._finish(); return _this._finish();
} }
if (_this._allDronesFinished()) { if (_this._allDronesFinished()) {
console.log("ALL DRONES EXITED"); console.log("ALL DRONES DOWN");
_this._result_message += "ALL DRONES DOWN!";
return _this._finish();
}
if (_this._allFlagsCaptured()) {
console.log("ALL FLAGS CAPTURED");
_this._result_message += "ALL FLAGS CAPTURED!";
return _this._finish(); return _this._finish();
} }
}); });
...@@ -674,7 +984,7 @@ var GameManager = /** @class */ (function () { ...@@ -674,7 +984,7 @@ var GameManager = /** @class */ (function () {
seconds = Math.floor(this._game_duration / 1000), trace_objects; seconds = Math.floor(this._game_duration / 1000), trace_objects;
if (GAMEPARAMETERS.log_drone_flight || GAMEPARAMETERS.draw_flight_path) { if (GAMEPARAMETERS.log_drone_flight || GAMEPARAMETERS.draw_flight_path) {
this._droneList.forEach(function (drone, index) { this._droneList_user.forEach(function (drone, index) {
if (drone.can_play) { if (drone.can_play) {
drone_position = drone.position; drone_position = drone.position;
if (GAMEPARAMETERS.log_drone_flight) { if (GAMEPARAMETERS.log_drone_flight) {
...@@ -687,8 +997,7 @@ var GameManager = /** @class */ (function () { ...@@ -687,8 +997,7 @@ var GameManager = /** @class */ (function () {
geo_coordinates = map_manager.convertToGeoCoordinates( geo_coordinates = map_manager.convertToGeoCoordinates(
drone_position.x, drone_position.x,
drone_position.y, drone_position.y,
drone_position.z, drone_position.z
map_info
); );
game_manager._flight_log[index].push([ game_manager._flight_log[index].push([
game_manager._game_duration, geo_coordinates.x, game_manager._game_duration, geo_coordinates.x,
...@@ -711,12 +1020,14 @@ var GameManager = /** @class */ (function () { ...@@ -711,12 +1020,14 @@ var GameManager = /** @class */ (function () {
position_obj.position = new BABYLON.Vector3(drone_position.x, position_obj.position = new BABYLON.Vector3(drone_position.x,
drone_position.z, drone_position.z,
drone_position.y); drone_position.y);
//TODO base it on map_size
position_obj.scaling = new BABYLON.Vector3(4, 4, 4); position_obj.scaling = new BABYLON.Vector3(4, 4, 4);
material = new BABYLON.StandardMaterial(game_manager._scene); material = new BABYLON.StandardMaterial(game_manager._scene);
material.alpha = 1; material.alpha = 1;
color = new BABYLON.Color3(255, 0, 0); color = new BABYLON.Color3(255, 0, 0);
if (game_manager._colors[index]) { var color_index = index % 10;
color = game_manager._colors[index]; if (game_manager._colors[color_index]) {
color = game_manager._colors[color_index];
} }
material.diffuseColor = color; material.diffuseColor = color;
position_obj.material = material; position_obj.material = material;
...@@ -742,7 +1053,7 @@ var GameManager = /** @class */ (function () { ...@@ -742,7 +1053,7 @@ var GameManager = /** @class */ (function () {
GameManager.prototype._allDronesFinished = function () { GameManager.prototype._allDronesFinished = function () {
var finish = true; var finish = true;
this._droneList.forEach(function (drone) { this._droneList_user.forEach(function (drone) {
if (drone.can_play) { if (drone.can_play) {
finish = false; finish = false;
} }
...@@ -750,8 +1061,31 @@ var GameManager = /** @class */ (function () { ...@@ -750,8 +1061,31 @@ var GameManager = /** @class */ (function () {
return finish; return finish;
}; };
GameManager.prototype._allFlagsCaptured = function () {
var finish = true;
this._mapManager._flag_list.forEach(function (flag) {
//do not use flag weight for now, just 1 hit is enough
if (flag.drone_collider_list.length === 0) {
//if (flag.drone_collider_list.length < flag.weight) {
finish = false;
}
});
return finish;
};
GameManager.prototype._calculateUserScore = function () {
var score = 0;
this._droneList_user.forEach(function (drone) {
//if (drone.can_play) {
score += drone.score;
//}
});
return score;
};
GameManager.prototype._finish = function () { GameManager.prototype._finish = function () {
console.log("Simulation finished"); console.log("Simulation finished");
this._result_message += " User score: " + this._calculateUserScore();
this._canUpdate = false; this._canUpdate = false;
return this.finish_deferred.resolve(); return this.finish_deferred.resolve();
}; };
...@@ -763,7 +1097,8 @@ var GameManager = /** @class */ (function () { ...@@ -763,7 +1097,8 @@ var GameManager = /** @class */ (function () {
}; };
GameManager.prototype._init = function () { GameManager.prototype._init = function () {
var _this = this, canvas, hemi_north, hemi_south, camera, on3DmodelsReady; var _this = this,
canvas, hemi_north, hemi_south, camera, cam_radius, on3DmodelsReady;
canvas = this._canvas; canvas = this._canvas;
this._delayed_defer_list = []; this._delayed_defer_list = [];
this._dispose(); this._dispose();
...@@ -775,6 +1110,9 @@ var GameManager = /** @class */ (function () { ...@@ -775,6 +1110,9 @@ var GameManager = /** @class */ (function () {
audioEngine: false audioEngine: false
}); });
this._scene = new BABYLON.Scene(this._engine); this._scene = new BABYLON.Scene(this._engine);
//for DEBUG - fondo negro
//this._scene.clearColor = BABYLON.Color3.Black();
//deep ground color - light blue simile sky
this._scene.clearColor = new BABYLON.Color4( this._scene.clearColor = new BABYLON.Color4(
88 / 255, 88 / 255,
171 / 255, 171 / 255,
...@@ -797,13 +1135,18 @@ var GameManager = /** @class */ (function () { ...@@ -797,13 +1135,18 @@ var GameManager = /** @class */ (function () {
this._scene this._scene
); );
hemi_south.intensity = 0.75; hemi_south.intensity = 0.75;
camera = new BABYLON.ArcRotateCamera("camera", 0, 1.25, 800, cam_radius = (GAMEPARAMETERS.map.map_size * 1.10 < 6000) ?
GAMEPARAMETERS.map.map_size * 1.10 : 6000; //skybox scene limit
camera = new BABYLON.ArcRotateCamera("camera", 0, 1.25, cam_radius,
BABYLON.Vector3.Zero(), this._scene); BABYLON.Vector3.Zero(), this._scene);
camera.wheelPrecision = 10; camera.wheelPrecision = 10;
//zoom out limit
camera.upperRadiusLimit = GAMEPARAMETERS.map.map_size * 10;
//scene.activeCamera.upperRadiusLimit = max * 4;
//changed for event handling //changed for event handling
//camera.attachControl(this._scene.getEngine().getRenderingCanvas()); //orig //camera.attachControl(this._scene.getEngine().getRenderingCanvas()); //orig
camera.attachControl(canvas, true); camera.attachControl(canvas, true);
camera.maxz = 40000; camera.maxz = 400000;
this._camera = camera; this._camera = camera;
// Render loop // Render loop
...@@ -819,8 +1162,9 @@ var GameManager = /** @class */ (function () { ...@@ -819,8 +1162,9 @@ var GameManager = /** @class */ (function () {
} }
// Init the map // Init the map
_this._mapManager = new MapManager(ctx._scene); _this._mapManager = new MapManager(ctx._scene);
ctx._spawnDrones(_this._mapManager.map_info.initial_position, ctx._spawnDrones(_this._mapManager.getMapInfo().initial_position,
GAMEPARAMETERS.droneList, ctx); GAMEPARAMETERS.map.drones.user, TEAM_USER, ctx);
ctx._spawnDrones(null, GAMEPARAMETERS.map.drones.enemy, TEAM_ENEMY, ctx);
// Hide the drone prefab // Hide the drone prefab
DroneManager.Prefab.isVisible = false; DroneManager.Prefab.isVisible = false;
//Hack to make advanced texture work //Hack to make advanced texture work
...@@ -833,23 +1177,37 @@ var GameManager = /** @class */ (function () { ...@@ -833,23 +1177,37 @@ var GameManager = /** @class */ (function () {
ctx._scene ctx._scene
); );
document = documentTmp; document = documentTmp;
for (count = 0; count < GAMEPARAMETERS.droneList.length; count += 1) { function colourDrones(drone_list, colour) {
controlMesh = ctx._droneList[count].infosMesh; for (count = 0; count < drone_list.length; count += 1) {
controlMesh = drone_list[count].infosMesh;
rect = new BABYLON.GUI.Rectangle(); rect = new BABYLON.GUI.Rectangle();
rect.width = "10px"; rect.width = "10px";
rect.height = "10px"; rect.height = "10px";
rect.cornerRadius = 20; rect.cornerRadius = 20;
rect.color = "white"; rect.color = "white";
rect.thickness = 0.5; rect.thickness = 0.5;
rect.background = "grey"; rect.background = colour;
advancedTexture.addControl(rect);
rect.linkWithMesh(controlMesh);
}
}
function colourFlags(flag_list) {
for (count = 0; count < flag_list.length; count += 1) {
controlMesh = flag_list[count].subMeshes[0]._mesh;
rect = new BABYLON.GUI.Rectangle();
rect.width = "15px";
rect.height = "10px";
rect.cornerRadius = 1;
rect.color = "white";
rect.thickness = 0.5;
rect.background = "green";
advancedTexture.addControl(rect); advancedTexture.addControl(rect);
label = new BABYLON.GUI.TextBlock();
label.text = count.toString();
label.fontSize = 7;
rect.addControl(label);
rect.linkWithMesh(controlMesh); rect.linkWithMesh(controlMesh);
rect.linkOffsetY = 0;
} }
}
colourFlags(_this._mapManager._flag_list);
colourDrones(ctx._droneList_user, "blue");
colourDrones(ctx._droneList_enemy, "red");
console.log("on3DmodelsReady - advaced textures added"); console.log("on3DmodelsReady - advaced textures added");
return ctx; return ctx;
}; };
...@@ -862,6 +1220,8 @@ var GameManager = /** @class */ (function () { ...@@ -862,6 +1220,8 @@ var GameManager = /** @class */ (function () {
}) })
.push(function () { .push(function () {
on3DmodelsReady(_this); on3DmodelsReady(_this);
_this._droneList =
_this._droneList_user.concat(_this._droneList_enemy);
var result = new RSVP.Queue(); var result = new RSVP.Queue();
result.push(function () { result.push(function () {
return RSVP.delay(1000); return RSVP.delay(1000);
...@@ -871,7 +1231,7 @@ var GameManager = /** @class */ (function () { ...@@ -871,7 +1231,7 @@ var GameManager = /** @class */ (function () {
}; };
GameManager.prototype._start = function () { GameManager.prototype._start = function () {
var _this = this, promise_list; var _this = this, promise_list, start_msg;
_this.waiting_update_count = 0; _this.waiting_update_count = 0;
_this.ongoing_update_promise = null; _this.ongoing_update_promise = null;
_this.finish_deferred = RSVP.defer(); _this.finish_deferred = RSVP.defer();
...@@ -882,11 +1242,17 @@ var GameManager = /** @class */ (function () { ...@@ -882,11 +1242,17 @@ var GameManager = /** @class */ (function () {
return new RSVP.Queue() return new RSVP.Queue()
.push(function () { .push(function () {
promise_list = []; promise_list = [];
_this._droneList.forEach(function (drone) { _this._droneList_user.forEach(function (drone) {
drone._tick = 0; drone._tick = 0;
promise_list.push(drone.internal_start( promise_list.push(drone.internal_start());
_this._mapManager.getMapInfo().initial_position });
)); start_msg = {
'flag_positions': _this._mapManager.getMapInfo().geo_flag_list
};
promise_list.push(_this._droneList_user[0].sendMsg(start_msg));
_this._droneList_enemy.forEach(function (drone) {
drone._tick = 0;
promise_list.push(drone.internal_start());
}); });
return RSVP.all(promise_list); return RSVP.all(promise_list);
}) })
...@@ -941,9 +1307,10 @@ var GameManager = /** @class */ (function () { ...@@ -941,9 +1307,10 @@ var GameManager = /** @class */ (function () {
return parameter; return parameter;
}; };
GameManager.prototype._spawnDrones = function (center, drone_list, ctx) { GameManager.prototype._spawnDrones = function (init_position, drone_list,
team, ctx, drone_location) {
var position, i, position_list = [], max_collision = 10 * drone_list.length, var position, i, position_list = [], max_collision = 10 * drone_list.length,
collision_nb = 0, api; collision_nb = 0, api, center;
function checkCollision(position, list) { function checkCollision(position, list) {
var el; var el;
for (el = 0; el < list.length; el += 1) { for (el = 0; el < list.length; el += 1) {
...@@ -953,7 +1320,7 @@ var GameManager = /** @class */ (function () { ...@@ -953,7 +1320,7 @@ var GameManager = /** @class */ (function () {
} }
return false; return false;
} }
function spawnDrone(x, y, z, index, drone_info, api) { function spawnDrone(x, y, z, index, drone_info, api, team) {
var default_drone_AI = api.getDroneAI(), code, base, code_eval; var default_drone_AI = api.getDroneAI(), code, base, code_eval;
if (default_drone_AI) { if (default_drone_AI) {
code = default_drone_AI; code = default_drone_AI;
...@@ -961,9 +1328,9 @@ var GameManager = /** @class */ (function () { ...@@ -961,9 +1328,9 @@ var GameManager = /** @class */ (function () {
code = drone_info.script_content; code = drone_info.script_content;
} }
code_eval = "let drone = new DroneManager(ctx._scene, " + code_eval = "let drone = new DroneManager(ctx._scene, " +
index + ', api);' + index + ', api, team);' +
"let droneMe = function(NativeDate, me, Math, window, DroneManager," + "let droneMe = function(NativeDate, me, Math, window, DroneManager," +
" GameManager, FixedWingDroneAPI, BABYLON, " + " GameManager, FixedWingDroneAPI, EnemyDroneAPI, BABYLON, " +
"GAMEPARAMETERS) {" + "GAMEPARAMETERS) {" +
"var start_time = (new Date(2070, 0, 0, 0, 0, 0, 0)).getTime();" + "var start_time = (new Date(2070, 0, 0, 0, 0, 0, 0)).getTime();" +
"Date.now = function () {" + "Date.now = function () {" +
...@@ -980,8 +1347,8 @@ var GameManager = /** @class */ (function () { ...@@ -980,8 +1347,8 @@ var GameManager = /** @class */ (function () {
} }
base = code_eval; base = code_eval;
code_eval += code + "}; droneMe(Date, drone, Math, {});"; code_eval += code + "}; droneMe(Date, drone, Math, {});";
base += "};ctx._droneList.push(drone)"; base += "};ctx._droneList_" + team + ".push(drone)";
code_eval += "ctx._droneList.push(drone)"; code_eval += "ctx._droneList_" + team + ".push(drone)";
/*jslint evil: true*/ /*jslint evil: true*/
try { try {
eval(code_eval); eval(code_eval);
...@@ -1001,6 +1368,11 @@ var GameManager = /** @class */ (function () { ...@@ -1001,6 +1368,11 @@ var GameManager = /** @class */ (function () {
return new BABYLON.Vector3(x, y, z); return new BABYLON.Vector3(x, y, z);
} }
for (i = 0; i < drone_list.length; i += 1) { for (i = 0; i < drone_list.length; i += 1) {
if (!init_position) {
center = drone_list[i].position;
} else {
center = init_position;
}
position = randomSpherePoint(center.x + i, center.y + i, center.z + i, position = randomSpherePoint(center.x + i, center.y + i, center.z + i,
0, 0, 0); 0, 0, 0);
if (checkCollision(position, position_list)) { if (checkCollision(position, position_list)) {
...@@ -1010,14 +1382,18 @@ var GameManager = /** @class */ (function () { ...@@ -1010,14 +1382,18 @@ var GameManager = /** @class */ (function () {
} }
} else { } else {
position_list.push(position); position_list.push(position);
var id_offset = 0;
if (team == TEAM_ENEMY) {
id_offset = GAMEPARAMETERS.map.drones.user.length;
}
api = new this.APIs_dict[drone_list[i].type]( api = new this.APIs_dict[drone_list[i].type](
this, this,
drone_list[i], drone_list[i],
GAMEPARAMETERS, GAMEPARAMETERS,
i i + id_offset
); );
spawnDrone(position.x, position.y, position.z, i, spawnDrone(position.x, position.y, position.z, i + id_offset,
drone_list[i], api); drone_list[i], api, team);
} }
} }
}; };
...@@ -1043,15 +1419,15 @@ var runGame, updateGame; ...@@ -1043,15 +1419,15 @@ var runGame, updateGame;
return game_manager_instance.run(); return game_manager_instance.run();
}; };
updateGame = function () { updateGame = function (fullscreen) {
if (game_manager_instance) { if (game_manager_instance) {
return game_manager_instance.update(); return game_manager_instance.update(fullscreen);
} }
}; };
/*// Resize canvas on window resize /*// Resize canvas on window resize
window.addEventListener('resize', function () { window.addEventListener('resize', function () {
engine.resize(); game_manager_instance._engine.resize();
});*/ });*/
......
...@@ -246,7 +246,7 @@ ...@@ -246,7 +246,7 @@
</item> </item>
<item> <item>
<key> <string>serial</string> </key> <key> <string>serial</string> </key>
<value> <string>1007.63308.6371.35532</string> </value> <value> <string>1010.5086.1058.34440</string> </value>
</item> </item>
<item> <item>
<key> <string>state</string> </key> <key> <string>state</string> </key>
...@@ -266,7 +266,7 @@ ...@@ -266,7 +266,7 @@
</tuple> </tuple>
<state> <state>
<tuple> <tuple>
<float>1682437964.37</float> <float>1690567567.2</float>
<string>UTC</string> <string>UTC</string>
</tuple> </tuple>
</state> </state>
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
<script src="jiodev.js" type="text/javascript"></script> <script src="jiodev.js" type="text/javascript"></script>
<script src="gadget_global.js" type="text/javascript"></script> <script src="gadget_global.js" type="text/javascript"></script>
<script src="domsugar.js" type="text/javascript"></script> <script src="domsugar.js" type="text/javascript"></script>
<script type="text/javascript" src="./libraries/seedrandom.min.js"></script>
<script src="gadget_erp5_page_drone_capture_flag_script_page.js" type="text/javascript"></script> <script src="gadget_erp5_page_drone_capture_flag_script_page.js" type="text/javascript"></script>
......
...@@ -244,7 +244,7 @@ ...@@ -244,7 +244,7 @@
</item> </item>
<item> <item>
<key> <string>serial</string> </key> <key> <string>serial</string> </key>
<value> <string>1007.63297.49586.20838</string> </value> <value> <string>1008.22253.2281.60074</string> </value>
</item> </item>
<item> <item>
<key> <string>state</string> </key> <key> <string>state</string> </key>
...@@ -264,7 +264,7 @@ ...@@ -264,7 +264,7 @@
</tuple> </tuple>
<state> <state>
<tuple> <tuple>
<float>1682436612.47</float> <float>1683820259.6</float>
<string>UTC</string> <string>UTC</string>
</tuple> </tuple>
</state> </state>
......
/*jslint indent: 2, maxlen: 100*/ /*jslint indent: 2, maxlen: 100*/
/*global window, rJS, domsugar, document, Blob*/ /*global window, rJS, domsugar, document, URLSearchParams, Blob*/
(function (window, rJS, domsugar, document, Blob) { (function (window, rJS, domsugar, document, URLSearchParams, Blob) {
"use strict"; "use strict";
//Default values - TODO: get them from the drone API //Drone default values - TODO: get them from the drone API
var SIMULATION_SPEED = 200, var SIMULATION_SPEED = 10,
SIMULATION_TIME = 1500, SIMULATION_TIME = 270,
min_lat = 45.6364, MAP_SIZE = 600,
max_lat = 45.65, map_height = 700,
min_lon = 14.2521,
max_lon = 14.2766,
map_height = 100,
start_AMSL = 595, start_AMSL = 595,
DEFAULT_SPEED = 16, DEFAULT_SPEED = 16,
MAX_ACCELERATION = 6, MAX_ACCELERATION = 6,
...@@ -22,65 +19,20 @@ ...@@ -22,65 +19,20 @@
MAX_PITCH = 25, MAX_PITCH = 25,
MAX_CLIMB_RATE = 8, MAX_CLIMB_RATE = 8,
MAX_SINK_RATE = 3, MAX_SINK_RATE = 3,
INITIAL_POSITION = { NUMBER_OF_DRONES = 10,
"latitude": 45.6412, FLAG_WEIGHT = 5,
"longitude": 14.2658, SEED = '6',
"z": 15
},
NUMBER_OF_DRONES = 2,
// Non-inputs parameters // Non-inputs parameters
DEFAULT_SCRIPT_CONTENT = DEFAULT_SCRIPT_CONTENT =
'var ALTITUDE = 100,\n' + 'var EPSILON = 15,\n' +
' EPSILON = 9,\n' + ' DODGE_DISTANCE = 100;\n' +
' CHECKPOINT_LIST = [\n' +
' {\n' +
' altitude: 585.1806861589965,\n' +
' latitude: 45.64492790560583,\n' +
' longitude: 14.25334942966329\n' +
' },\n' +
' {\n' +
' altitude: 589.8802607573035,\n' +
' latitude: 45.64316335436476,\n' +
' longitude: 14.26332880184475\n' +
' },\n' +
' {\n' +
' altitude: 608.6648153348965,\n' +
' latitude: 45.64911917196595,\n' +
' longitude: 14.26214792790128\n' +
' },\n' +
' {\n' +
' altitude: 606.1448368129072,\n' +
' latitude: 45.64122685351364,\n' +
' longitude: 14.26590493128597\n' +
' },\n' +
' {\n' +
' altitude: 630.0829598206344,\n' +
' latitude: 45.64543355564817,\n' +
' longitude: 14.27242391207985\n' +
' },\n' +
' {\n' +
' altitude: 616.1839898415284,\n' +
' latitude: 45.6372792927328,\n' +
' longitude: 14.27533492411138\n' +
' },\n' +
' {\n' +
' altitude: 598.0603137354178,\n' +
' latitude: 45.64061299543953,\n' +
' longitude: 14.26161958465814\n' +
' },\n' +
' {\n' +
' altitude: 607.1243119862851,\n' +
' latitude: 45.64032340702919,\n' +
' longitude: 14.2682896662383\n' +
' }\n' +
' ];\n' +
'\n' + '\n' +
'function distance(lat1, lon1, lat2, lon2) {\n' + 'function distance(a, b) {\n' +
' var R = 6371e3, // meters\n' + ' var R = 6371e3, // meters\n' +
' la1 = lat1 * Math.PI / 180, // lat, lon in radians\n' + ' la1 = a.x * Math.PI / 180, // lat, lon in radians\n' +
' la2 = lat2 * Math.PI / 180,\n' + ' la2 = b.x * Math.PI / 180,\n' +
' lo1 = lon1 * Math.PI / 180,\n' + ' lo1 = a.y * Math.PI / 180,\n' +
' lo2 = lon2 * Math.PI / 180,\n' + ' lo2 = b.y * Math.PI / 180,\n' +
' haversine_phi = Math.pow(Math.sin((la2 - la1) / 2), 2),\n' + ' haversine_phi = Math.pow(Math.sin((la2 - la1) / 2), 2),\n' +
' sin_lon = Math.sin((lo2 - lo1) / 2),\n' + ' sin_lon = Math.sin((lo2 - lo1) / 2),\n' +
' h = haversine_phi + Math.cos(la1) * Math.cos(la2) * sin_lon * sin_lon;\n' + ' h = haversine_phi + Math.cos(la1) * Math.cos(la2) * sin_lon * sin_lon;\n' +
...@@ -89,49 +41,88 @@ ...@@ -89,49 +41,88 @@
'\n' + '\n' +
'me.onStart = function () {\n' + 'me.onStart = function () {\n' +
' me.direction_set = false;\n' + ' me.direction_set = false;\n' +
' me.next_checkpoint = 0;\n' + ' me.dodging = false;\n' +
' me.ongoing_detection = false;\n' +
'};\n' +
'\n' +
'me.onGetMsg = function (msg) {\n' +
' if (msg && msg.flag_positions) {\n' +
' me.flag_positions = msg.flag_positions\n' +
' me.next_checkpoint = me.id % me.flag_positions.length;\n' +
' }\n' +
'};\n' + '};\n' +
'\n' + '\n' +
'me.onUpdate = function (timestamp) {' + 'me.onUpdate = function (timestamp) {\n' +
' if (!me.flag_positions) return;\n' +
' if (me.dodging) {\n' +
' me.current_position = me.getCurrentPosition();\n' +
' var dist = distance(\n' +
' me.current_position,\n' +
' me.dodging.position\n' +
' );\n' +
' if (dist >= DODGE_DISTANCE) {\n' +
//' console.log("Good distance to obstacle. DODGED.");\n' +
' me.dodging = false;\n' +
' }\n' +
' return;\n' +
' }\n' +
' if (!me.direction_set) {\n' + ' if (!me.direction_set) {\n' +
' if (me.next_checkpoint < CHECKPOINT_LIST.length) {\n' + ' if (me.next_checkpoint < me.flag_positions.length) {\n' +
' me.setTargetCoordinates(\n' + ' me.setTargetCoordinates(\n' +
' CHECKPOINT_LIST[me.next_checkpoint].latitude,\n' + ' me.flag_positions[me.next_checkpoint].x,\n' +
' CHECKPOINT_LIST[me.next_checkpoint].longitude,\n' + ' me.flag_positions[me.next_checkpoint].y,\n' +
' CHECKPOINT_LIST[me.next_checkpoint].altitude + ALTITUDE + ALTITUDE * me.id\n' + ' me.flag_positions[me.next_checkpoint].z + me.id\n' +
' );\n' + ' );\n' +
' console.log("[DEMO] Going to Checkpoint %d", me.next_checkpoint);\n' + //' console.log("[DEMO] Going to Checkpoint %d", me.next_checkpoint);\n' +
' }\n' + ' }\n' +
' me.direction_set = true;\n' + ' me.direction_set = true;\n' +
' return;\n' + ' return;\n' +
' }\n' + ' }\n' +
' if (me.next_checkpoint < CHECKPOINT_LIST.length) {\n' + ' if (me.next_checkpoint < me.flag_positions.length) {\n' +
' if (!me.ongoing_detection) {\n' +
' me.getDroneViewInfo();\n' +
' me.ongoing_detection = true;\n' +
' }\n' +
' }\n' +
' if (me.next_checkpoint < me.flag_positions.length) {\n' +
' me.current_position = me.getCurrentPosition();\n' + ' me.current_position = me.getCurrentPosition();\n' +
' me.distance = distance(\n' + ' me.distance = distance(\n' +
' me.current_position.x,\n' + ' me.current_position,\n' +
' me.current_position.y,\n' + ' me.flag_positions[me.next_checkpoint]\n' +
' CHECKPOINT_LIST[me.next_checkpoint].latitude,\n' +
' CHECKPOINT_LIST[me.next_checkpoint].longitude\n' +
' );\n' + ' );\n' +
' if (me.distance <= EPSILON) {\n' + ' if (me.distance <= EPSILON) {\n' +
' console.log("[DEMO] Reached Checkpoint %d", me.next_checkpoint);\n' + //' console.log("[DEMO] Reached Checkpoint %d", me.next_checkpoint);\n' +
' me.next_checkpoint += 1;\n' + ' me.next_checkpoint += 1;\n' +
' me.direction_set = false;\n' + ' me.direction_set = false;\n' +
' }\n' + ' }\n' +
' return;\n' + ' return;\n' +
' }\n' + ' }\n' +
' me.exit(0);\n' + '};\n' +
'\n' +
'me.onDroneViewInfo = function (drone_view) {\n' +
' me.ongoing_detection = false;\n' +
' if (drone_view && drone_view.obstacles && drone_view.obstacles.length) {\n' +
' me.dodging = drone_view.obstacles[0];\n' +
' me.direction_set = false;\n' +
' var random = Math.random() < 0.5, dodge_point = {};\n' +
' Object.assign(dodge_point, me.flag_positions[me.next_checkpoint]);\n' +
' if (random) {\n' +
' dodge_point.x = dodge_point.x * -1;\n' +
' } else {\n' +
' dodge_point.y = dodge_point.y * -1;\n' +
' }\n' +
' me.setTargetCoordinates(dodge_point.x, dodge_point.y, me.getCurrentPosition().z);\n' +
' return;\n' +
' }\n' +
'};', '};',
DRAW = true, DRAW = true,
LOG = true, LOG = true,
LOG_TIME = 1662.7915426540285, LOG_TIME = 1662.7915426540285,
DRONE_LIST = [], DRONE_LIST = [],
WIDTH = 680,
HEIGHT = 340,
LOGIC_FILE_LIST = [ LOGIC_FILE_LIST = [
'gadget_erp5_page_drone_capture_flag_logic.js', 'gadget_erp5_page_drone_capture_flag_logic.js',
'gadget_erp5_page_drone_capture_flag_fixedwingdrone.js'/*, 'gadget_erp5_page_drone_capture_flag_fixedwingdrone.js',
'gadget_erp5_page_drone_capture_flag_dronelogfollower.js'*/ 'gadget_erp5_page_drone_capture_flag_enemydrone.js'
]; ];
rJS(window) rJS(window)
...@@ -161,7 +152,8 @@ ...@@ -161,7 +152,8 @@
}) })
.declareMethod('render', function render() { .declareMethod('render', function render() {
var gadget = this; var gadget = this, url_sp = new URLSearchParams(window.location.hash),
url_seed = url_sp.get("seed");
return gadget.getDeclaredGadget('form_view') return gadget.getDeclaredGadget('form_view')
.push(function (form_gadget) { .push(function (form_gadget) {
return form_gadget.render({ return form_gadget.render({
...@@ -299,60 +291,38 @@ ...@@ -299,60 +291,38 @@
"hidden": 0, "hidden": 0,
"type": "FloatField" "type": "FloatField"
}, },
"my_minimum_latitud": { "my_map_size": {
"description": "",
"title": "Minimum latitude",
"default": min_lat,
"css_class": "",
"required": 1,
"editable": 1,
"key": "min_lat",
"hidden": 0,
"type": "FloatField"
},
"my_maximum_latitud": {
"description": "",
"title": "Maximum latitude",
"default": max_lat,
"css_class": "",
"required": 1,
"editable": 1,
"key": "max_lat",
"hidden": 0,
"type": "FloatField"
},
"my_minimum_longitud": {
"description": "", "description": "",
"title": "Minimum longitude", "title": "Map size",
"default": min_lon, "default": MAP_SIZE,
"css_class": "", "css_class": "",
"required": 1, "required": 1,
"editable": 1, "editable": 1,
"key": "min_lon", "key": "map_size",
"hidden": 0, "hidden": 0,
"type": "FloatField" "type": "FloatField"
}, },
"my_maximum_longitud": { "my_start_AMSL": {
"description": "", "description": "",
"title": "Maximum longitude", "title": "Start AMSL",
"default": max_lon, "default": start_AMSL,
"css_class": "", "css_class": "",
"required": 1, "required": 1,
"editable": 1, "editable": 1,
"key": "max_lon", "key": "start_AMSL",
"hidden": 0, "hidden": 0,
"type": "FloatField" "type": "FloatField"
}, },
"my_start_AMSL": { "my_map_seed": {
"description": "", "description": "Seed value to randomize the map",
"title": "Start AMSL", "title": "Seed value",
"default": start_AMSL, "default": url_seed ? url_seed : SEED,
"css_class": "", "css_class": "",
"required": 1, "required": 1,
"editable": 1, "editable": 1,
"key": "start_AMSL", "key": "map_seed",
"hidden": 0, "hidden": 0,
"type": "FloatField" "type": "StringField"
}, },
"my_map_height": { "my_map_height": {
"description": "", "description": "",
...@@ -365,39 +335,17 @@ ...@@ -365,39 +335,17 @@
"hidden": 0, "hidden": 0,
"type": "IntegerField" "type": "IntegerField"
}, },
"my_init_pos_lon": { /*"my_flag_weight": {
"description": "", "description": "",
"title": "Initial drone longitude", "title": "Flag Weight",
"default": INITIAL_POSITION.longitude, "default": FLAG_WEIGHT,
"css_class": "", "css_class": "",
"required": 1, "required": 1,
"editable": 1, "editable": 1,
"key": "init_pos_lon", "key": "flag_weight",
"hidden": 0, "hidden": 0,
"type": "FloatField" "type": "IntegerField"
}, },*/
"my_init_pos_lat": {
"description": "",
"title": "Initial drone latitude",
"default": INITIAL_POSITION.latitude,
"css_class": "",
"required": 1,
"editable": 1,
"key": "init_pos_lat",
"hidden": 0,
"type": "FloatField"
},
"my_init_pos_z": {
"description": "",
"title": "Initial drone position Z",
"default": INITIAL_POSITION.z,
"css_class": "",
"required": 1,
"editable": 1,
"key": "init_pos_z",
"hidden": 0,
"type": "FloatField"
},
"my_number_of_drones": { "my_number_of_drones": {
"description": "", "description": "",
"title": "Number of drones", "title": "Number of drones",
...@@ -432,13 +380,11 @@ ...@@ -432,13 +380,11 @@
group_list: [[ group_list: [[
"left", "left",
[["my_simulation_speed"], ["my_simulation_time"], ["my_number_of_drones"], [["my_simulation_speed"], ["my_simulation_time"], ["my_number_of_drones"],
["my_minimum_latitud"], ["my_maximum_latitud"], ["my_map_size"], ["my_map_height"],// ["my_flag_weight"],
["my_minimum_longitud"], ["my_maximum_longitud"], ["my_start_AMSL"], ["my_map_seed"]]
["my_init_pos_lat"], ["my_init_pos_lon"], ["my_init_pos_z"],
["my_map_height"]]
], [ ], [
"right", "right",
[["my_start_AMSL"], ["my_drone_min_speed"], ["my_drone_speed"], ["my_drone_max_speed"], [["my_drone_min_speed"], ["my_drone_speed"], ["my_drone_max_speed"],
["my_drone_max_acceleration"], ["my_drone_max_deceleration"], ["my_drone_max_acceleration"], ["my_drone_max_deceleration"],
["my_drone_max_roll"], ["my_drone_min_pitch"], ["my_drone_max_pitch"], ["my_drone_max_roll"], ["my_drone_min_pitch"], ["my_drone_max_pitch"],
["my_drone_max_sink_rate"], ["my_drone_max_climb_rate"]] ["my_drone_max_sink_rate"], ["my_drone_max_climb_rate"]]
...@@ -460,14 +406,119 @@ ...@@ -460,14 +406,119 @@
.declareJob('runGame', function runGame(options) { .declareJob('runGame', function runGame(options) {
var gadget = this, i, var gadget = this, i,
fragment = gadget.element.querySelector('.simulator_div'), fragment = gadget.element.querySelector('.simulator_div'),
game_parameters_json; game_parameters_json, map_json;
DRONE_LIST = [];
fragment = domsugar(gadget.element.querySelector('.simulator_div'), fragment = domsugar(gadget.element.querySelector('.simulator_div'),
[domsugar('div')]).firstElementChild; [domsugar('div')]).firstElementChild;
DRONE_LIST = [];
for (i = 0; i < options.number_of_drones; i += 1) { for (i = 0; i < options.number_of_drones; i += 1) {
DRONE_LIST[i] = {"id": i, "type": "FixedWingDroneAPI", DRONE_LIST[i] = {"id": i, "type": "FixedWingDroneAPI",
"script_content": options.script}; "script_content": options.script};
} }
function randomizeMap(json_map) {
function randomIntFromInterval(min, max, random_seed) {
return Math.floor(random_seed.quick() * (max - min + 1) + min);
}
function randomPosition(random_seed, map_size) {
var sign_x = random_seed.quick() < 0.5 ? -1 : 1,
sign_y = random_seed.quick() < 0.5 ? -1 : 1,
pos_x = sign_x * random_seed.quick() * map_size / 2,
pos_y = sign_y * random_seed.quick() * map_size / 2;
return [pos_x, pos_y];
}
var seed_value = options.map_seed,
random_seed = new Math.seedrandom(seed_value), i,
n_enemies = randomIntFromInterval(5, 10, random_seed),
n_flags = randomIntFromInterval(Math.floor(DRONE_LIST.length / 2),
DRONE_LIST.length, random_seed),
n_obstacles = randomIntFromInterval(5, 15, random_seed),
flag_list = [], obstacle_list = [], enemy_list = [], random_position,
obstacles_types = ["box"/*, "sphere"*/, "cylinder"], type,
obstacle_limit = [options.map_size / 6, options.map_size / 100,
options.map_size / 6, 30];
//enemies
for (i = 0; i < n_enemies; i += 1) {
random_position = randomPosition(random_seed, options.map_size);
enemy_list.push({
"id": i + parseInt(options.number_of_drones),
"type": "EnemyDroneAPI",
"position": {
"x": random_position[0],
"y": random_position[1],
"z": 15 //TODO random z?
}
});
}
//flags
for (i = 0; i < n_flags; i += 1) {
//avoid flags near the limits
random_position = randomPosition(random_seed, options.map_size * 0.75);
flag_list.push({
"position": {
"x": random_position[0],
"y": random_position[1],
"z": 10
}
});
}
function checkDistance(position, position_list) {
function distance(a, b) {
return Math.sqrt((a.x - b.x) ** 2 + (a.y - b.y) ** 2);
}
var el;
for (el = 0; el < position_list.length; el += 1) {
if (distance(position, position_list[el].position) < options.map_size / 6) {
return true;
}
}
return false;
}
//obstacles
for (i = 0; i < n_obstacles; i += 1) {
random_position = randomPosition(random_seed, options.map_size);
if (checkDistance({ 'x': random_position[0],
'y': random_position[1]}, flag_list)) {
i -= 1;
} else {
type = randomIntFromInterval(0, 2, random_seed);
obstacle_list.push({
"type": obstacles_types[type],
"position": {
"x": random_position[0],
"y": random_position[1],
"z": 15 //TODO random z?
},
"scale": {
"x": randomIntFromInterval(20, obstacle_limit[type], random_seed),
"y": randomIntFromInterval(20, obstacle_limit[type], random_seed),
"z": randomIntFromInterval(5, obstacle_limit[3], random_seed)
},
"rotation": {
"x": 0,
"y": 0,
"z": 0
}
});
}
}
json_map.obstacle_list = obstacle_list;
json_map.drones.enemy = enemy_list;
json_map.flag_list = flag_list;
return json_map;
}
map_json = {
"map_size": parseFloat(options.map_size),
"height": parseInt(options.map_height, 10),
"start_AMSL": parseFloat(options.start_AMSL),
"flag_list": [],
"obstacle_list" : [],
"drones": {
"user": DRONE_LIST,
"enemy": []
}
};
game_parameters_json = { game_parameters_json = {
"drone": { "drone": {
"maxAcceleration": parseInt(options.drone_max_acceleration, 10), "maxAcceleration": parseInt(options.drone_max_acceleration, 10),
...@@ -487,24 +538,11 @@ ...@@ -487,24 +538,11 @@
"information": 0, "information": 0,
"communication": 0 "communication": 0
}, },
"map": { "map": randomizeMap(map_json),
"min_lat": parseFloat(options.min_lat),
"max_lat": parseFloat(options.max_lat),
"min_lon": parseFloat(options.min_lon),
"max_lon": parseFloat(options.max_lon),
"height": parseInt(options.map_height, 10),
"start_AMSL": parseFloat(options.start_AMSL)
},
"initialPosition": {
"longitude": parseFloat(options.init_pos_lon),
"latitude": parseFloat(options.init_pos_lat),
"z": parseFloat(options.init_pos_z)
},
"draw_flight_path": DRAW, "draw_flight_path": DRAW,
"temp_flight_path": true, "temp_flight_path": true,
"log_drone_flight": LOG, "log_drone_flight": LOG,
"log_interval_time": LOG_TIME, "log_interval_time": LOG_TIME
"droneList": DRONE_LIST
}; };
return gadget.declareGadget("babylonjs.gadget.html", return gadget.declareGadget("babylonjs.gadget.html",
{element: fragment, scope: 'simulator'}) {element: fragment, scope: 'simulator'})
...@@ -525,8 +563,7 @@ ...@@ -525,8 +563,7 @@
"type": "GadgetField", "type": "GadgetField",
"url": "babylonjs.gadget.html", "url": "babylonjs.gadget.html",
"sandbox": "public", "sandbox": "public",
"renderjs_extra": '{"autorun": false, "width": ' + WIDTH + ', ' + "renderjs_extra": '{"autorun": false, ' +
'"height": ' + HEIGHT + ', ' +
'"logic_file_list": ' + JSON.stringify(LOGIC_FILE_LIST) + ', ' + '"logic_file_list": ' + JSON.stringify(LOGIC_FILE_LIST) + ', ' +
'"game_parameters": ' + JSON.stringify(game_parameters_json) + '"game_parameters": ' + JSON.stringify(game_parameters_json) +
'}' '}'
...@@ -553,35 +590,44 @@ ...@@ -553,35 +590,44 @@
return form_gadget.getContent(); return form_gadget.getContent();
}) })
.push(function (result) { .push(function (result) {
var a, blob, div, key, log, log_content; var a, blob, div, key, log, log_content, aux;
i = 0; i = 0;
for (key in result) { div = domsugar('div', { text: result.message });
if (result.hasOwnProperty(key)) { document.querySelector('.container').parentNode.appendChild(div);
log_content = result[key].join('\n').replaceAll(",", ";"); for (key in result.content) {
if (result.content.hasOwnProperty(key)) {
log_content = result.content[key].join('\n').replaceAll(",", ";");
blob = new Blob([log_content], {type: 'text/plain'}); blob = new Blob([log_content], {type: 'text/plain'});
a = domsugar('a', { a = domsugar('a', {
text: 'Download Simulation LOG ' + i, text: 'Download Simulation LOG ' + i,
download: 'simulation_log_' + i download: 'simulation_log_' + i +
+ '_speed_' + game_parameters_json.drone.speed '_speed_' + game_parameters_json.drone.speed +
+ '_min-speed_' + game_parameters_json.drone.minSpeed '_min-speed_' + game_parameters_json.drone.minSpeed +
+ '_max-speed_' + game_parameters_json.drone.maxSpeed '_max-speed_' + game_parameters_json.drone.maxSpeed +
+ '_max-accel_' + game_parameters_json.drone.maxAcceleration '_max-accel_' + game_parameters_json.drone.maxAcceleration +
+ '_max-decel_' + game_parameters_json.drone.maxDeceleration '_max-decel_' + game_parameters_json.drone.maxDeceleration +
+ '_max-roll_' + game_parameters_json.drone.maxRoll '_max-roll_' + game_parameters_json.drone.maxRoll +
+ '_min-pitch_' + game_parameters_json.drone.minPitchAngle '_min-pitch_' + game_parameters_json.drone.minPitchAngle +
+ '_max-pitch_' + game_parameters_json.drone.maxPitchAngle '_max-pitch_' + game_parameters_json.drone.maxPitchAngle +
+ '_max-sink_' + game_parameters_json.drone.maxSinkRate '_max-sink_' + game_parameters_json.drone.maxSinkRate +
+ '_max-climb_' + game_parameters_json.drone.maxClimbRate '_max-climb_' + game_parameters_json.drone.maxClimbRate +
+ '.txt', '.txt',
href: window.URL.createObjectURL(blob) href: window.URL.createObjectURL(blob)
}); });
log = domsugar('textarea', { value: log_content, id: 'log_result_' + i }); log = domsugar('textarea',
{ value: log_content, id: 'log_result_' + i });
div = domsugar('div', [a]); div = domsugar('div', [a]);
a.dataset.downloadurl = ['text/plain', a.download, a.dataset.downloadurl = ['text/plain', a.download,
a.href].join(':'); a.href].join(':');
document.querySelector('.container').appendChild(div); document.querySelector('.container').parentNode.appendChild(div);
document.querySelector('.container').appendChild(log); document.querySelector('.container').parentNode.appendChild(log);
i += 1; i += 1;
if (i === DRONE_LIST.length) {
break;
//Do not show enemy drone logs for now
/*aux = domsugar('div', { text: "Enemy drones logs:" });
document.querySelector('.container').parentNode.appendChild(aux);*/
}
} }
} }
}, function (error) { }, function (error) {
...@@ -590,4 +636,4 @@ ...@@ -590,4 +636,4 @@
}); });
}); });
}(window, rJS, domsugar, document, Blob)); }(window, rJS, domsugar, document, URLSearchParams, Blob));
\ No newline at end of file \ No newline at end of file
...@@ -246,7 +246,7 @@ ...@@ -246,7 +246,7 @@
</item> </item>
<item> <item>
<key> <string>serial</string> </key> <key> <string>serial</string> </key>
<value> <string>1007.63299.40871.39799</string> </value> <value> <string>1009.57725.14056.1911</string> </value>
</item> </item>
<item> <item>
<key> <string>state</string> </key> <key> <string>state</string> </key>
...@@ -266,7 +266,7 @@ ...@@ -266,7 +266,7 @@
</tuple> </tuple>
<state> <state>
<tuple> <tuple>
<float>1682437874.39</float> <float>1689793877.59</float>
<string>UTC</string> <string>UTC</string>
</tuple> </tuple>
</state> </state>
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
</item> </item>
<item> <item>
<key> <string>height</string> </key> <key> <string>height</string> </key>
<value> <int>512</int> </value> <value> <int>1024</int> </value>
</item> </item>
<item> <item>
<key> <string>precondition</string> </key> <key> <string>precondition</string> </key>
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
</item> </item>
<item> <item>
<key> <string>width</string> </key> <key> <string>width</string> </key>
<value> <int>512</int> </value> <value> <int>1024</int> </value>
</item> </item>
</dictionary> </dictionary>
</pickle> </pickle>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Folder" module="OFS.Folder"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_objects</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>libraries</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
!function(f,a,c){var s,l=256,p="random",d=c.pow(l,6),g=c.pow(2,52),y=2*g,h=l-1;function n(n,t,r){function e(){for(var n=u.g(6),t=d,r=0;n<g;)n=(n+r)*l,t*=l,r=u.g(1);for(;y<=n;)n/=2,t/=2,r>>>=1;return(n+r)/t}var o=[],i=j(function n(t,r){var e,o=[],i=typeof t;if(r&&"object"==i)for(e in t)try{o.push(n(t[e],r-1))}catch(n){}return o.length?o:"string"==i?t:t+"\0"}((t=1==t?{entropy:!0}:t||{}).entropy?[n,S(a)]:null==n?function(){try{var n;return s&&(n=s.randomBytes)?n=n(l):(n=new Uint8Array(l),(f.crypto||f.msCrypto).getRandomValues(n)),S(n)}catch(n){var t=f.navigator,r=t&&t.plugins;return[+new Date,f,r,f.screen,S(a)]}}():n,3),o),u=new m(o);return e.int32=function(){return 0|u.g(4)},e.quick=function(){return u.g(4)/4294967296},e.double=e,j(S(u.S),a),(t.pass||r||function(n,t,r,e){return e&&(e.S&&v(e,u),n.state=function(){return v(u,{})}),r?(c[p]=n,t):n})(e,i,"global"in t?t.global:this==c,t.state)}function m(n){var t,r=n.length,u=this,e=0,o=u.i=u.j=0,i=u.S=[];for(r||(n=[r++]);e<l;)i[e]=e++;for(e=0;e<l;e++)i[e]=i[o=h&o+n[e%r]+(t=i[e])],i[o]=t;(u.g=function(n){for(var t,r=0,e=u.i,o=u.j,i=u.S;n--;)t=i[e=h&e+1],r=r*l+i[h&(i[e]=i[o=h&o+t])+(i[o]=t)];return u.i=e,u.j=o,r})(l)}function v(n,t){return t.i=n.i,t.j=n.j,t.S=n.S.slice(),t}function j(n,t){for(var r,e=n+"",o=0;o<e.length;)t[h&o]=h&(r^=19*t[h&o])+e.charCodeAt(o++);return S(t)}function S(n){return String.fromCharCode.apply(0,n)}if(j(c.random(),a),"object"==typeof module&&module.exports){module.exports=n;try{s=require("crypto")}catch(n){}}else"function"==typeof define&&define.amd?define(function(){return n}):c["seed"+p]=n}("undefined"!=typeof self?self:this,[],Math);
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="File" module="OFS.Image"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>__name__</string> </key>
<value> <string>seedrandom.min.js</string> </value>
</item>
<item>
<key> <string>content_type</string> </key>
<value> <string>application/javascript</string> </value>
</item>
<item>
<key> <string>precondition</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment