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 @@
var FixedWingDroneAPI = /** @class */ (function () {
"use strict";
// var TAKEOFF_RADIUS = 60,
var DEFAULT_SPEED = 16,
EARTH_GRAVITY = 9.81,
LOITER_LIMIT = 30,
LOITER_RADIUS_FACTOR = 0.60,
LOITER_SPEED_FACTOR = 1.5,
MAX_ACCELERATION = 6,
MAX_DECELERATION = 1,
MIN_SPEED = 12,
......@@ -19,7 +16,8 @@ var FixedWingDroneAPI = /** @class */ (function () {
MIN_PITCH = -20,
MAX_PITCH = 25,
MAX_CLIMB_RATE = 8,
MAX_SINK_RATE = 3;
MAX_SINK_RATE = 3,
VIEW_SCOPE = 100;
//** CONSTRUCTOR
function FixedWingDroneAPI(gameManager, drone_info, flight_parameters, id) {
......@@ -29,10 +27,8 @@ var FixedWingDroneAPI = /** @class */ (function () {
this._flight_parameters = flight_parameters;
this._id = id;
this._drone_info = drone_info;
this._loiter_radius = 0;
this._last_loiter_point_reached = -1;
this._loiter_radius = 100;
//this._start_altitude = 0;
//this._last_altitude_point_reached = -1;
this._loiter_mode = false;
this._drone_dict_list = [];
}
......@@ -40,6 +36,7 @@ var FixedWingDroneAPI = /** @class */ (function () {
** Function called on start phase of the drone, just before onStart AI script
*/
FixedWingDroneAPI.prototype.internal_start = function (drone) {
drone._targetCoordinates = drone.getCurrentPosition();
drone._maxDeceleration = this.getMaxDeceleration();
if (drone._maxDeceleration <= 0) {
throw new Error('max deceleration must be superior to 0');
......@@ -146,9 +143,6 @@ var FixedWingDroneAPI = /** @class */ (function () {
*/
FixedWingDroneAPI.prototype.internal_post_update = function (drone) {
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
_this.reachAltitude(drone);
}*/
......@@ -158,7 +152,10 @@ var FixedWingDroneAPI = /** @class */ (function () {
'altitudeAbs' : _this._mapManager.getMapInfo().start_AMSL +
drone_position.z,
'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;
//broadcast drone info using internal msg
......@@ -171,7 +168,7 @@ var FixedWingDroneAPI = /** @class */ (function () {
};
FixedWingDroneAPI.prototype._updateSpeed = function (drone, delta_time) {
var speed = drone.getSpeed(), speedDiff, speedUpdate;
var speed = drone.getAirSpeed(), speedDiff, speedUpdate;
if (speed !== this._targetSpeed) {
speedDiff = this._targetSpeed - speed;
speedUpdate = drone._acceleration * delta_time / 1000;
......@@ -185,13 +182,30 @@ var FixedWingDroneAPI = /** @class */ (function () {
};
FixedWingDroneAPI.prototype._updateDirection = function (drone, delta_time) {
var horizontalCoeff, newX, newY, newZ;
[newX, newZ] = this._getNewYaw(drone, delta_time);
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);
}
newY = this._getNewAltitude(drone);
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)
)
......@@ -235,14 +249,14 @@ var FixedWingDroneAPI = /** @class */ (function () {
verticalSpeed = this._computeVerticalSpeed(
altitudeDiff,
this.getMaxClimbRate(),
drone.getSpeed(),
drone.getAirSpeed(),
this.getMaxPitchAngle()
);
} else {
verticalSpeed = -this._computeVerticalSpeed(
Math.abs(altitudeDiff),
this.getMaxSinkRate(),
drone.getSpeed(),
drone.getAirSpeed(),
-this.getMinPitchAngle()
);
}
......@@ -261,18 +275,14 @@ var FixedWingDroneAPI = /** @class */ (function () {
drone.rotation.z + y);
};
FixedWingDroneAPI.prototype.setAltitude = function (drone, altitude) {
drone._targetCoordinates.z = altitude;
};
FixedWingDroneAPI.prototype.setSpeed = function (drone, speed) {
this._targetSpeed = Math.max(
Math.min(speed, this.getMaxSpeed()),
this.getMinSpeed()
);
drone._acceleration = (this._targetSpeed > drone.getSpeed())
? this.getMaxAcceleration() : -this.getMaxDeceleration();
drone._acceleration = (this._targetSpeed > drone.getAirSpeed()) ?
this.getMaxAcceleration() : -this.getMaxDeceleration();
};
FixedWingDroneAPI.prototype.setStartingPosition = function (drone, x, y, z) {
......@@ -290,34 +300,18 @@ var FixedWingDroneAPI = /** @class */ (function () {
this._drone_dict_list[id] = msg;
};
FixedWingDroneAPI.prototype.set_loiter_mode = function (radius) {
this._loiter_mode = true;
if (radius && radius > LOITER_LIMIT) {
this._loiter_radius = radius * LOITER_RADIUS_FACTOR;
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)
);
}
}
};
FixedWingDroneAPI.prototype.internal_setTargetCoordinates =
function (drone, coordinates, loiter) {
if (!loiter) {
function (drone, coordinates, radius) {
if (radius) {
this._loiter_mode = true;
if (radius >= LOITER_LIMIT) {
this._loiter_radius = radius;
}
} else {
this._loiter_mode = false;
//save last target point to use as next loiter center
this._last_target = coordinates;
}
};
FixedWingDroneAPI.prototype.sendMsg = function (msg, to) {
var _this = this,
droneList = _this._gameManager._droneList;
......@@ -362,79 +356,59 @@ var FixedWingDroneAPI = /** @class */ (function () {
if (isNaN(lat) || isNaN(lon) || isNaN(z)) {
throw new Error('Target coordinates must be numbers');
}
var x = this._mapManager.longitudToX(lon, this._map_dict.width),
y = this._mapManager.latitudeToY(lat, this._map_dict.depth),
position = this._mapManager.normalize(x, y, this._map_dict),
processed_coordinates;
var point = this._mapManager.toLocalCoordinates(lat, lon,
this._map_dict.map_size),
position = this._mapManager.normalize(point.x, point.y, this._map_dict);
if (z > this._map_dict.start_AMSL) {
z -= this._map_dict.start_AMSL;
}
processed_coordinates = {
return {
x: position[0],
y: position[1],
z: z
};
//this._last_altitude_point_reached = -1;
//this.takeoff_path = [];
return processed_coordinates;
};
FixedWingDroneAPI.prototype.getCurrentPosition = function (x, y, z) {
return this._mapManager.convertToGeoCoordinates(x, y, z, this._map_dict);
};
FixedWingDroneAPI.prototype.loiter = function (drone) {
if (this._loiter_radius > LOITER_LIMIT) {
var drone_pos = drone.getCurrentPosition(),
min = 9999,
min_i,
i,
d,
next_point;
//shift loiter circle to nearest point
if (this._last_loiter_point_reached === -1) {
if (!this.shifted) {
drone._maxSpeed = drone._maxSpeed * LOITER_SPEED_FACTOR;
for (i = 0; i < this._loiter_coordinates.length; i += 1) {
d = this._mapManager.latLonDistance([drone_pos.x, drone_pos.y],
[this._loiter_coordinates[i].x,
this._loiter_coordinates[i].y]);
if (d < min) {
min = d;
min_i = i;
}
}
this._loiter_coordinates = this._loiter_coordinates.concat(
this._loiter_coordinates.splice(0, min_i)
);
this.shifted = true;
FixedWingDroneAPI.prototype.getDroneViewInfo = function (drone) {
var context = this, result = { "obstacles": [], "drones": [] }, distance,
other_position, drone_position = drone.getCurrentPosition();
function calculateDistance(a, b, _this) {
return _this._mapManager.latLonDistance([a.x, a.y], [b.x, b.y]);
}
context._gameManager._droneList.forEach(function (other) {
if (other.can_play && drone.id != other.id) {
other_position = other.getCurrentPosition();
distance = calculateDistance(drone_position, other_position, context);
if (distance <= VIEW_SCOPE) {
result.drones.push({
position: drone.getCurrentPosition(),
direction: drone.direction,
rotation: drone.rotation,
speed: drone.speed,
team: drone.team
});
}
} 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;
});
context._map_dict.geo_obstacle_list.forEach(function (obstacle) {
distance = calculateDistance(drone_position, obstacle.position, context);
if (distance <= VIEW_SCOPE) {
result.obstacles.push(obstacle);
}
//loiter
next_point =
this._loiter_coordinates[this._last_loiter_point_reached + 1];
this.internal_setTargetCoordinates(drone, next_point, true);
if (this._mapManager.latLonDistance([drone_pos.x, drone_pos.y],
[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;
});
if (drone.__is_getting_drone_view !== true) {
drone.__is_getting_drone_view = 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();
}
next_point = this._loiter_coordinates[
this._last_loiter_point_reached + 1
];
this.internal_setTargetCoordinates(drone, next_point, true);
}
}, 1000);
}
};
FixedWingDroneAPI.prototype.getDroneAI = function () {
......@@ -475,9 +449,9 @@ var FixedWingDroneAPI = /** @class */ (function () {
return Math.PI / 4;
};
FixedWingDroneAPI.prototype.getYawVelocity = function (drone) {
return 360 * EARTH_GRAVITY
* Math.tan(this._toRad(this.getMaxRollAngle()))
/ (2 * Math.PI * drone.getSpeed());
return 360 * EARTH_GRAVITY *
Math.tan(this._toRad(this.getMaxRollAngle())) /
(2 * Math.PI * drone.getAirSpeed());
};
FixedWingDroneAPI.prototype.getYaw = function (drone) {
var direction = drone.worldDirection;
......@@ -493,9 +467,10 @@ var FixedWingDroneAPI = /** @class */ (function () {
};
FixedWingDroneAPI.prototype._computeVerticalSpeed =
function (altitude_diff, max_climb_rate, speed, max_pitch) {
var maxVerticalSpeed = Math.min(altitude_diff, Math.min(max_climb_rate, speed));
return (this._toDeg(Math.asin(maxVerticalSpeed / speed)) > max_pitch)
? speed * Math.sin(this._toRad(max_pitch))
var maxVerticalSpeed =
Math.min(altitude_diff, Math.min(max_climb_rate, speed));
return (this._toDeg(Math.asin(maxVerticalSpeed / speed)) > max_pitch) ?
speed * Math.sin(this._toRad(max_pitch))
: maxVerticalSpeed;
};
FixedWingDroneAPI.prototype._toRad = function (angle) {
......@@ -505,13 +480,13 @@ var FixedWingDroneAPI = /** @class */ (function () {
return angle * 180 / Math.PI;
};
FixedWingDroneAPI.prototype.getClimbRate = function (drone) {
return drone.worldDirection.y * drone.getSpeed();
return drone.worldDirection.y * drone.getAirSpeed();
};
FixedWingDroneAPI.prototype.getGroundSpeed = function (drone) {
var direction = drone.worldDirection;
return Math.sqrt(
Math.pow(direction.x * drone.getSpeed(), 2)
+ Math.pow(direction.z * drone.getSpeed(), 2)
Math.pow(direction.x * drone.getAirSpeed(), 2) +
Math.pow(direction.z * drone.getAirSpeed(), 2)
);
};
FixedWingDroneAPI.prototype.triggerParachute = function (drone) {
......@@ -526,10 +501,10 @@ var FixedWingDroneAPI = /** @class */ (function () {
return;
};
FixedWingDroneAPI.prototype.getInitialAltitude = function () {
return 0;
return this._map_dict.start_AMSL;
};
FixedWingDroneAPI.prototype.getAltitudeAbs = function (altitude) {
return altitude;
return altitude + this._map_dict.start_AMSL;
};
FixedWingDroneAPI.prototype.getMinHeight = function () {
return 0;
......
......@@ -246,7 +246,7 @@
</item>
<item>
<key> <string>serial</string> </key>
<value> <string>1007.63305.59225.51968</string> </value>
<value> <string>1010.5034.64121.33006</string> </value>
</item>
<item>
<key> <string>state</string> </key>
......@@ -266,7 +266,7 @@
</tuple>
<state>
<tuple>
<float>1682437182.61</float>
<float>1690565260.64</float>
<string>UTC</string>
</tuple>
</state>
......
/*global BABYLON, RSVP, console, FixedWingDroneAPI, document*/
/*global BABYLON, RSVP, console, FixedWingDroneAPI, EnemyDroneAPI, document*/
/*jslint nomen: true, indent: 2, maxlen: 80, todo: 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 ********************************/
var DroneManager = /** @class */ (function () {
"use strict";
//** CONSTRUCTOR
function DroneManager(scene, id, API) {
function DroneManager(scene, id, API, team) {
this._mesh = null;
this._controlMesh = null;
this._canPlay = false;
......@@ -31,8 +33,9 @@ var DroneManager = /** @class */ (function () {
this._scene = scene;
this._canUpdate = true;
this._id = id;
this._leader_id = 0;
this._team = team;
this._API = API; // var API created on AI evel
this._score = 0;
// Create the control mesh
this._controlMesh = BABYLON.Mesh.CreateBox(
"droneControl_" + id,
......@@ -61,11 +64,6 @@ var DroneManager = /** @class */ (function () {
// swap y and z axis so z axis represents altitude
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", {
get: function () { return this._API._drone_dict_list; },
enumerable: true,
......@@ -73,6 +71,7 @@ var DroneManager = /** @class */ (function () {
});
Object.defineProperty(DroneManager.prototype, "can_play", {
get: function () { return this._canPlay; },
set: function (value) { this._canPlay = value; },
enumerable: true,
configurable: true
});
......@@ -81,6 +80,17 @@ var DroneManager = /** @class */ (function () {
enumerable: 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", {
get: function () { return this._mesh; },
enumerable: true,
......@@ -124,11 +134,10 @@ var DroneManager = /** @class */ (function () {
enumerable: true,
configurable: true
});
DroneManager.prototype.internal_start = function (initial_position) {
DroneManager.prototype.internal_start = function () {
this._API.internal_start(this);
this._canPlay = true;
this._canCommunicate = true;
this._targetCoordinates = initial_position;
try {
return this.onStart();
} catch (error) {
......@@ -140,15 +149,30 @@ var DroneManager = /** @class */ (function () {
* Set a target point to move
*/
DroneManager.prototype.setTargetCoordinates = function (x, y, z) {
if (!this._canPlay) {
return;
this._internal_setTargetCoordinates(x, y, z);
};
DroneManager.prototype._internal_setTargetCoordinates =
function (x, y, z, radius) {
if (!this._canPlay) {
return;
}
//convert real geo-coordinates to virtual x-y coordinates
this._targetCoordinates = this._API.processCoordinates(x, y, z);
return this._API.internal_setTargetCoordinates(
this,
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);
}
//convert real geo-coordinates to virtual x-y coordinates
this._targetCoordinates = this._API.processCoordinates(x, y, z);
return this._API.internal_setTargetCoordinates(
this,
this._targetCoordinates
);
return;
};
DroneManager.prototype.internal_update = function (delta_time) {
var context = this;
......@@ -194,7 +218,7 @@ var DroneManager = /** @class */ (function () {
}
return this._API.setStartingPosition(this, x, y, z);
};
DroneManager.prototype.setSpeed = function (speed) {
DroneManager.prototype.setAirSpeed = function (speed) {
if (!this._canPlay) {
return;
}
......@@ -292,20 +316,11 @@ var DroneManager = /** @class */ (function () {
}
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)
*/
DroneManager.prototype.loiter = function (radius) {
if (!this._canPlay) {
return;
}
this._API.set_loiter_mode(radius);
DroneManager.prototype.loiter = function (x, y, z, radius) {
this._internal_setTargetCoordinates(x, y, z, radius);
};
DroneManager.prototype.getFlightParameters = function () {
if (this._API.getFlightParameters) {
......@@ -314,19 +329,31 @@ var DroneManager = /** @class */ (function () {
return null;
};
DroneManager.prototype.getYaw = function () {
return this._API.getYaw(this);
if (typeof this._API.getYaw !== "undefined") {
return this._API.getYaw(this);
}
return;
};
DroneManager.prototype.getSpeed = function () {
DroneManager.prototype.getAirSpeed = function () {
return this._speed;
};
DroneManager.prototype.getGroundSpeed = function () {
return this._API.getGroundSpeed(this);
if (typeof this._API.getGroundSpeed !== "undefined") {
return this._API.getGroundSpeed(this);
}
return;
};
DroneManager.prototype.getClimbRate = function () {
return this._API.getClimbRate(this);
if (typeof this._API.getClimbRate !== "undefined") {
return this._API.getClimbRate(this);
}
return;
};
DroneManager.prototype.getSinkRate = function () {
return this._API.getSinkRate();
if (typeof this._API.getSinkRate !== "undefined") {
return this._API.getSinkRate(this);
}
return;
};
DroneManager.prototype.triggerParachute = function () {
return this._API.triggerParachute(this);
......@@ -364,6 +391,12 @@ var DroneManager = /** @class */ (function () {
* @param msg The message
*/
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;
}());
......@@ -375,41 +408,70 @@ var DroneManager = /** @class */ (function () {
var MapManager = /** @class */ (function () {
"use strict";
function calculateMapInfo(map, map_dict, initial_position) {
var max_width = map.latLonDistance([map_dict.min_lat, map_dict.min_lon],
[map_dict.min_lat, map_dict.max_lon]),
max_height = map.latLonDistance([map_dict.min_lat, map_dict.min_lon],
[map_dict.max_lat, map_dict.min_lon]),
map_size = Math.ceil(Math.max(max_width, max_height)) * 0.6,
map_info = {
"depth": map_size,
"height": map_dict.height,
"width": map_size,
"map_size": map_size,
"min_x": map.longitudToX(map_dict.min_lon, map_size),
"min_y": map.latitudeToY(map_dict.min_lat, map_size),
"max_x": map.longitudToX(map_dict.max_lon, map_size),
"max_y": map.latitudeToY(map_dict.max_lat, map_size),
"start_AMSL": map_dict.start_AMSL
},
position = map.normalize(
map.longitudToX(initial_position.longitude, map_size),
map.latitudeToY(initial_position.latitude, map_size),
map_info
);
map_info.initial_position = {
"x": position[0],
"y": position[1],
"z": initial_position.z
//random geo-point:
var MIN_LAT = 45.64,
MIN_LON = 14.253,
EPSILON = 9.9,
START_Z = 15,
R = 6371e3;
function calculateMapInfo(map, map_dict) {
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,
"start_AMSL": map_dict.start_AMSL,
"flag_list": map_dict.flag_list,
"geo_flag_list": [],
"flag_distance_epsilon": map_dict.flag_distance_epsilon || EPSILON,
"obstacle_list": map_dict.obstacle_list,
"geo_obstacle_list": [],
"initial_position": {
"x": 0,
"y": starting_point,
"z": START_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
function MapManager(scene) {
var _this = this, max_sky, skybox, skyboxMat, largeGroundMat,
largeGroundBottom, width, depth, terrain, max;
_this.map_info = calculateMapInfo(_this, GAMEPARAMETERS.map,
GAMEPARAMETERS.initialPosition);
var _this = this, max_sky, skybox, skyboxMat, largeGroundMat, flag_material,
largeGroundBottom, width, depth, terrain, max, flag_a, flag_b, mast, flag,
count = 0, new_obstacle;
calculateMapInfo(_this, GAMEPARAMETERS.map);
max = _this.map_info.width;
if (_this.map_info.depth > max) {
max = _this.map_info.depth;
......@@ -419,30 +481,29 @@ var MapManager = /** @class */ (function () {
}
max = max < _this.map_info.depth ? _this.map_info.depth : max;
// Skybox
max_sky = (max * 10 < 20000) ? max * 10 : 20000;
skybox = BABYLON.Mesh.CreateBox("skyBox", max_sky, scene);
skybox.infiniteDistance = true;
skybox.renderingGroupId = 0;
max_sky = (max * 15 < 20000) ? max * 15 : 20000; //skybox scene limit
skybox = BABYLON.MeshBuilder.CreateBox("skyBox", { size: max_sky }, scene);
skyboxMat = new BABYLON.StandardMaterial("skybox", scene);
skyboxMat.backFaceCulling = false;
skyboxMat.disableLighting = true;
skybox.material = skyboxMat;
skybox.infiniteDistance = true;
skyboxMat.disableLighting = true;
skyboxMat.reflectionTexture = new BABYLON.CubeTexture("./assets/skybox/sky",
scene);
skyboxMat.reflectionTexture.coordinatesMode = BABYLON.Texture.SKYBOX_MODE;
skyboxMat.infiniteDistance = true;
skybox.material = skyboxMat;
skybox.renderingGroupId = 0;
// Plane from bottom
largeGroundMat = new BABYLON.StandardMaterial("largeGroundMat", scene);
largeGroundMat.specularColor = BABYLON.Color3.Black();
largeGroundMat.alpha = 0.4;
largeGroundBottom = BABYLON.Mesh.CreatePlane("largeGroundBottom",
max * 11, scene);
max * 11, scene);
largeGroundBottom.position.y = -0.01;
largeGroundBottom.rotation.x = -Math.PI / 2;
largeGroundBottom.rotation.y = Math.PI;
largeGroundBottom.material = largeGroundMat;
// Camera
scene.activeCamera.upperRadiusLimit = max * 4;
largeGroundBottom.renderingGroupId = 1;
// Terrain
// Give map some margin from the flight limits
width = _this.map_info.width * 1.10;
......@@ -453,19 +514,122 @@ var MapManager = /** @class */ (function () {
terrain.position = BABYLON.Vector3.Zero();
terrain.scaling = new BABYLON.Vector3(depth / 50000, depth / 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 () {
return this.map_info;
};
MapManager.prototype.longitudToX = function (lon, map_size) {
return (map_size / 360.0) * (180 + lon);
MapManager.prototype.latLonOffset = function (lat, lon, offset_in_mt) {
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.latitudeToY = function (lat, map_size) {
return (map_size / 180.0) * (90 - lat);
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.latLonDistance = function (c1, c2) {
var R = 6371e3,
q1 = c1[0] * Math.PI / 180,
var q1 = c1[0] * Math.PI / 180,
q2 = c2[0] * Math.PI / 180,
dq = (c2[0] - c1[0]) * Math.PI / 180,
dl = (c2[1] - c1[1]) * Math.PI / 180,
......@@ -481,8 +645,9 @@ var MapManager = /** @class */ (function () {
return [n_x * 1000 - map_dict.width / 2,
n_y * 1000 - map_dict.depth / 2];
};
MapManager.prototype.convertToGeoCoordinates = function (x, y, z, map_dict) {
var lon = x + map_dict.width / 2,
MapManager.prototype.convertToGeoCoordinates = function (x, y, z) {
var map_dict = this.map_info,
lon = x + map_dict.width / 2,
lat = y + map_dict.depth / 2;
lon = lon / 1000;
lon = lon * (map_dict.max_x - map_dict.min_x) +
......@@ -511,11 +676,15 @@ var GameManager = /** @class */ (function () {
"use strict";
// *** CONSTRUCTOR ***
function GameManager(canvas, game_parameters_json) {
var drone, header_list;
var drone, header_list, drone_count;
this._canvas = canvas;
this._canvas_width = canvas.width;
this._canvas_height = canvas.height;
this._scene = null;
this._engine = null;
this._droneList = [];
this._droneList_user = [];
this._droneList_enemy = [];
this._canUpdate = false;
this._max_step_animation_frame = game_parameters_json.simulation_speed;
if (!this._max_step_animation_frame) { this._max_step_animation_frame = 5; }
......@@ -524,39 +693,55 @@ var GameManager = /** @class */ (function () {
this._map_swapped = false;
this._log_count = [];
this._flight_log = [];
if (GAMEPARAMETERS.draw_flight_path) {
this._last_position_drawn = [];
this._trace_objects_per_drone = [];
this._result_message = "";
if (GAMEPARAMETERS.log_drone_flight) {
// ! Be aware that the following functions relies on this log format:
// - getLogEntries at Drone Simulator Log Page
// - getLogEntries at Dron Log Follower API
// - getLogEntries at Drone Log Follower API
header_list = ["timestamp (ms)", "latitude (°)", "longitude (°)",
"AMSL (m)", "rel altitude (m)", "yaw (°)",
"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].push(header_list);
this._log_count[drone] = 0;
this._last_position_drawn[drone] = null;
this._trace_objects_per_drone[drone] = [];
}
this._colors = [
new BABYLON.Color3(255, 165, 0),
new BABYLON.Color3(0, 0, 255),
new BABYLON.Color3(255, 0, 0),
new BABYLON.Color3(0, 255, 0),
new BABYLON.Color3(0, 128, 128),
new BABYLON.Color3(0, 0, 0),
new BABYLON.Color3(255, 255, 255),
new BABYLON.Color3(128, 128, 0),
new BABYLON.Color3(128, 0, 128),
new BABYLON.Color3(0, 0, 128)
];
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._trace_objects_per_drone[drone] = [];
}
this._colors = [
new BABYLON.Color3(255, 165, 0),
new BABYLON.Color3(0, 0, 255),
new BABYLON.Color3(255, 0, 0),
new BABYLON.Color3(0, 255, 0),
new BABYLON.Color3(0, 128, 128),
new BABYLON.Color3(0, 0, 0),
new BABYLON.Color3(255, 255, 255),
new BABYLON.Color3(128, 128, 0),
new BABYLON.Color3(128, 0, 128),
new BABYLON.Color3(0, 0, 128)
];
}
}
this.APIs_dict = {
FixedWingDroneAPI: FixedWingDroneAPI/*,
DroneLogAPI: DroneLogAPI*/
FixedWingDroneAPI: FixedWingDroneAPI,
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", {
......@@ -571,11 +756,15 @@ var GameManager = /** @class */ (function () {
var gadget = this;
return gadget._init()
.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
// This is fixed and must not be modified
// otherwise, it will lead to different scenario results
......@@ -587,10 +776,8 @@ var GameManager = /** @class */ (function () {
function triggerUpdateIfPossible() {
if ((_this._canUpdate) && (_this.ongoing_update_promise === null) &&
(0 < _this.waiting_update_count)) {
_this.ongoing_update_promise = _this._update(
TIME_DELTA,
(_this.waiting_update_count === 1)
).push(function () {
_this.ongoing_update_promise = _this._update(TIME_DELTA, fullscreen)
.push(function () {
_this.waiting_update_count -= 1;
_this.ongoing_update_promise = null;
triggerUpdateIfPossible();
......@@ -617,16 +804,98 @@ var GameManager = /** @class */ (function () {
this._flight_log[drone._id].push(error.stack);
};
GameManager.prototype._checkDroneRules = function (drone) {
//TODO move this to API methods.
//each type of drone should define its rules
if (drone.getCurrentPosition()) {
return drone.getCurrentPosition().z > 1;
GameManager.prototype._checkDroneOut = function (drone) {
if (drone.position) {
var map_limit = this._mapManager.getMapInfo().map_size / 2;
return (drone.position.z > this._mapManager.getMapInfo().height) ||
(drone.position.x < -map_limit) ||
(drone.position.x > map_limit) ||
(drone.position.y < -map_limit) ||
(drone.position.y > map_limit);
}
return false;
};
GameManager.prototype._update = function (delta_time) {
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.'));
}*/
}
};
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,
queue = new RSVP.Queue(),
i;
......@@ -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) {
queue.push(function () {
var msg = '';
drone._tick += 1;
if (_this._checkDroneRules(drone)) {
return drone.internal_update(delta_time);
if (drone.can_play) {
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?
drone._internal_crash('Drone touched the floor');
return drone.internal_update(delta_time);
});
});
......@@ -657,10 +960,17 @@ var GameManager = /** @class */ (function () {
.push(function () {
if (_this._timeOut()) {
console.log("TIMEOUT!");
_this._result_message += "TIMEOUT!";
return _this._finish();
}
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();
}
});
......@@ -674,7 +984,7 @@ var GameManager = /** @class */ (function () {
seconds = Math.floor(this._game_duration / 1000), trace_objects;
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) {
drone_position = drone.position;
if (GAMEPARAMETERS.log_drone_flight) {
......@@ -687,8 +997,7 @@ var GameManager = /** @class */ (function () {
geo_coordinates = map_manager.convertToGeoCoordinates(
drone_position.x,
drone_position.y,
drone_position.z,
map_info
drone_position.z
);
game_manager._flight_log[index].push([
game_manager._game_duration, geo_coordinates.x,
......@@ -711,12 +1020,14 @@ var GameManager = /** @class */ (function () {
position_obj.position = new BABYLON.Vector3(drone_position.x,
drone_position.z,
drone_position.y);
//TODO base it on map_size
position_obj.scaling = new BABYLON.Vector3(4, 4, 4);
material = new BABYLON.StandardMaterial(game_manager._scene);
material.alpha = 1;
color = new BABYLON.Color3(255, 0, 0);
if (game_manager._colors[index]) {
color = game_manager._colors[index];
var color_index = index % 10;
if (game_manager._colors[color_index]) {
color = game_manager._colors[color_index];
}
material.diffuseColor = color;
position_obj.material = material;
......@@ -742,7 +1053,7 @@ var GameManager = /** @class */ (function () {
GameManager.prototype._allDronesFinished = function () {
var finish = true;
this._droneList.forEach(function (drone) {
this._droneList_user.forEach(function (drone) {
if (drone.can_play) {
finish = false;
}
......@@ -750,8 +1061,31 @@ var GameManager = /** @class */ (function () {
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 () {
console.log("Simulation finished");
this._result_message += " User score: " + this._calculateUserScore();
this._canUpdate = false;
return this.finish_deferred.resolve();
};
......@@ -763,7 +1097,8 @@ var GameManager = /** @class */ (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;
this._delayed_defer_list = [];
this._dispose();
......@@ -775,6 +1110,9 @@ var GameManager = /** @class */ (function () {
audioEngine: false
});
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(
88 / 255,
171 / 255,
......@@ -797,13 +1135,18 @@ var GameManager = /** @class */ (function () {
this._scene
);
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);
camera.wheelPrecision = 10;
//zoom out limit
camera.upperRadiusLimit = GAMEPARAMETERS.map.map_size * 10;
//scene.activeCamera.upperRadiusLimit = max * 4;
//changed for event handling
//camera.attachControl(this._scene.getEngine().getRenderingCanvas()); //orig
camera.attachControl(canvas, true);
camera.maxz = 40000;
camera.maxz = 400000;
this._camera = camera;
// Render loop
......@@ -819,8 +1162,9 @@ var GameManager = /** @class */ (function () {
}
// Init the map
_this._mapManager = new MapManager(ctx._scene);
ctx._spawnDrones(_this._mapManager.map_info.initial_position,
GAMEPARAMETERS.droneList, ctx);
ctx._spawnDrones(_this._mapManager.getMapInfo().initial_position,
GAMEPARAMETERS.map.drones.user, TEAM_USER, ctx);
ctx._spawnDrones(null, GAMEPARAMETERS.map.drones.enemy, TEAM_ENEMY, ctx);
// Hide the drone prefab
DroneManager.Prefab.isVisible = false;
//Hack to make advanced texture work
......@@ -833,23 +1177,37 @@ var GameManager = /** @class */ (function () {
ctx._scene
);
document = documentTmp;
for (count = 0; count < GAMEPARAMETERS.droneList.length; count += 1) {
controlMesh = ctx._droneList[count].infosMesh;
rect = new BABYLON.GUI.Rectangle();
rect.width = "10px";
rect.height = "10px";
rect.cornerRadius = 20;
rect.color = "white";
rect.thickness = 0.5;
rect.background = "grey";
advancedTexture.addControl(rect);
label = new BABYLON.GUI.TextBlock();
label.text = count.toString();
label.fontSize = 7;
rect.addControl(label);
rect.linkWithMesh(controlMesh);
rect.linkOffsetY = 0;
function colourDrones(drone_list, colour) {
for (count = 0; count < drone_list.length; count += 1) {
controlMesh = drone_list[count].infosMesh;
rect = new BABYLON.GUI.Rectangle();
rect.width = "10px";
rect.height = "10px";
rect.cornerRadius = 20;
rect.color = "white";
rect.thickness = 0.5;
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);
rect.linkWithMesh(controlMesh);
}
}
colourFlags(_this._mapManager._flag_list);
colourDrones(ctx._droneList_user, "blue");
colourDrones(ctx._droneList_enemy, "red");
console.log("on3DmodelsReady - advaced textures added");
return ctx;
};
......@@ -862,6 +1220,8 @@ var GameManager = /** @class */ (function () {
})
.push(function () {
on3DmodelsReady(_this);
_this._droneList =
_this._droneList_user.concat(_this._droneList_enemy);
var result = new RSVP.Queue();
result.push(function () {
return RSVP.delay(1000);
......@@ -871,7 +1231,7 @@ var GameManager = /** @class */ (function () {
};
GameManager.prototype._start = function () {
var _this = this, promise_list;
var _this = this, promise_list, start_msg;
_this.waiting_update_count = 0;
_this.ongoing_update_promise = null;
_this.finish_deferred = RSVP.defer();
......@@ -882,11 +1242,17 @@ var GameManager = /** @class */ (function () {
return new RSVP.Queue()
.push(function () {
promise_list = [];
_this._droneList.forEach(function (drone) {
_this._droneList_user.forEach(function (drone) {
drone._tick = 0;
promise_list.push(drone.internal_start());
});
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(
_this._mapManager.getMapInfo().initial_position
));
promise_list.push(drone.internal_start());
});
return RSVP.all(promise_list);
})
......@@ -941,9 +1307,10 @@ var GameManager = /** @class */ (function () {
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,
collision_nb = 0, api;
collision_nb = 0, api, center;
function checkCollision(position, list) {
var el;
for (el = 0; el < list.length; el += 1) {
......@@ -953,7 +1320,7 @@ var GameManager = /** @class */ (function () {
}
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;
if (default_drone_AI) {
code = default_drone_AI;
......@@ -961,9 +1328,9 @@ var GameManager = /** @class */ (function () {
code = drone_info.script_content;
}
code_eval = "let drone = new DroneManager(ctx._scene, " +
index + ', api);' +
index + ', api, team);' +
"let droneMe = function(NativeDate, me, Math, window, DroneManager," +
" GameManager, FixedWingDroneAPI, BABYLON, " +
" GameManager, FixedWingDroneAPI, EnemyDroneAPI, BABYLON, " +
"GAMEPARAMETERS) {" +
"var start_time = (new Date(2070, 0, 0, 0, 0, 0, 0)).getTime();" +
"Date.now = function () {" +
......@@ -980,8 +1347,8 @@ var GameManager = /** @class */ (function () {
}
base = code_eval;
code_eval += code + "}; droneMe(Date, drone, Math, {});";
base += "};ctx._droneList.push(drone)";
code_eval += "ctx._droneList.push(drone)";
base += "};ctx._droneList_" + team + ".push(drone)";
code_eval += "ctx._droneList_" + team + ".push(drone)";
/*jslint evil: true*/
try {
eval(code_eval);
......@@ -1001,6 +1368,11 @@ var GameManager = /** @class */ (function () {
return new BABYLON.Vector3(x, y, z);
}
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,
0, 0, 0);
if (checkCollision(position, position_list)) {
......@@ -1010,14 +1382,18 @@ var GameManager = /** @class */ (function () {
}
} else {
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](
this,
drone_list[i],
GAMEPARAMETERS,
i
i + id_offset
);
spawnDrone(position.x, position.y, position.z, i,
drone_list[i], api);
spawnDrone(position.x, position.y, position.z, i + id_offset,
drone_list[i], api, team);
}
}
};
......@@ -1043,15 +1419,15 @@ var runGame, updateGame;
return game_manager_instance.run();
};
updateGame = function () {
updateGame = function (fullscreen) {
if (game_manager_instance) {
return game_manager_instance.update();
return game_manager_instance.update(fullscreen);
}
};
/*// Resize canvas on window resize
window.addEventListener('resize', function () {
engine.resize();
game_manager_instance._engine.resize();
});*/
......
......@@ -246,7 +246,7 @@
</item>
<item>
<key> <string>serial</string> </key>
<value> <string>1007.63308.6371.35532</string> </value>
<value> <string>1010.5086.1058.34440</string> </value>
</item>
<item>
<key> <string>state</string> </key>
......@@ -266,7 +266,7 @@
</tuple>
<state>
<tuple>
<float>1682437964.37</float>
<float>1690567567.2</float>
<string>UTC</string>
</tuple>
</state>
......
......@@ -18,6 +18,7 @@
<script src="jiodev.js" type="text/javascript"></script>
<script src="gadget_global.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>
......
......@@ -244,7 +244,7 @@
</item>
<item>
<key> <string>serial</string> </key>
<value> <string>1007.63297.49586.20838</string> </value>
<value> <string>1008.22253.2281.60074</string> </value>
</item>
<item>
<key> <string>state</string> </key>
......@@ -264,7 +264,7 @@
</tuple>
<state>
<tuple>
<float>1682436612.47</float>
<float>1683820259.6</float>
<string>UTC</string>
</tuple>
</state>
......
/*jslint indent: 2, maxlen: 100*/
/*global window, rJS, domsugar, document, Blob*/
(function (window, rJS, domsugar, document, Blob) {
/*global window, rJS, domsugar, document, URLSearchParams, Blob*/
(function (window, rJS, domsugar, document, URLSearchParams, Blob) {
"use strict";
//Default values - TODO: get them from the drone API
var SIMULATION_SPEED = 200,
SIMULATION_TIME = 1500,
min_lat = 45.6364,
max_lat = 45.65,
min_lon = 14.2521,
max_lon = 14.2766,
map_height = 100,
//Drone default values - TODO: get them from the drone API
var SIMULATION_SPEED = 10,
SIMULATION_TIME = 270,
MAP_SIZE = 600,
map_height = 700,
start_AMSL = 595,
DEFAULT_SPEED = 16,
MAX_ACCELERATION = 6,
......@@ -22,65 +19,20 @@
MAX_PITCH = 25,
MAX_CLIMB_RATE = 8,
MAX_SINK_RATE = 3,
INITIAL_POSITION = {
"latitude": 45.6412,
"longitude": 14.2658,
"z": 15
},
NUMBER_OF_DRONES = 2,
NUMBER_OF_DRONES = 10,
FLAG_WEIGHT = 5,
SEED = '6',
// Non-inputs parameters
DEFAULT_SCRIPT_CONTENT =
'var ALTITUDE = 100,\n' +
' EPSILON = 9,\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' +
'var EPSILON = 15,\n' +
' DODGE_DISTANCE = 100;\n' +
'\n' +
'function distance(lat1, lon1, lat2, lon2) {\n' +
'function distance(a, b) {\n' +
' var R = 6371e3, // meters\n' +
' la1 = lat1 * Math.PI / 180, // lat, lon in radians\n' +
' la2 = lat2 * Math.PI / 180,\n' +
' lo1 = lon1 * Math.PI / 180,\n' +
' lo2 = lon2 * Math.PI / 180,\n' +
' la1 = a.x * Math.PI / 180, // lat, lon in radians\n' +
' la2 = b.x * Math.PI / 180,\n' +
' lo1 = a.y * Math.PI / 180,\n' +
' lo2 = b.y * Math.PI / 180,\n' +
' haversine_phi = Math.pow(Math.sin((la2 - la1) / 2), 2),\n' +
' sin_lon = Math.sin((lo2 - lo1) / 2),\n' +
' h = haversine_phi + Math.cos(la1) * Math.cos(la2) * sin_lon * sin_lon;\n' +
......@@ -89,49 +41,88 @@
'\n' +
'me.onStart = function () {\n' +
' me.direction_set = false;\n' +
' me.next_checkpoint = 0;\n' +
' me.dodging = false;\n' +
' me.ongoing_detection = false;\n' +
'};\n' +
'\n' +
'me.onUpdate = function (timestamp) {' +
'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' +
'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.next_checkpoint < CHECKPOINT_LIST.length) {\n' +
' if (me.next_checkpoint < me.flag_positions.length) {\n' +
' me.setTargetCoordinates(\n' +
' CHECKPOINT_LIST[me.next_checkpoint].latitude,\n' +
' CHECKPOINT_LIST[me.next_checkpoint].longitude,\n' +
' CHECKPOINT_LIST[me.next_checkpoint].altitude + ALTITUDE + ALTITUDE * me.id\n' +
' me.flag_positions[me.next_checkpoint].x,\n' +
' me.flag_positions[me.next_checkpoint].y,\n' +
' me.flag_positions[me.next_checkpoint].z + me.id\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' +
' me.direction_set = true;\n' +
' return;\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.distance = distance(\n' +
' me.current_position.x,\n' +
' me.current_position.y,\n' +
' CHECKPOINT_LIST[me.next_checkpoint].latitude,\n' +
' CHECKPOINT_LIST[me.next_checkpoint].longitude\n' +
' me.current_position,\n' +
' me.flag_positions[me.next_checkpoint]\n' +
' );\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.direction_set = false;\n' +
' }\n' +
' return;\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,
LOG = true,
LOG_TIME = 1662.7915426540285,
DRONE_LIST = [],
WIDTH = 680,
HEIGHT = 340,
LOGIC_FILE_LIST = [
'gadget_erp5_page_drone_capture_flag_logic.js',
'gadget_erp5_page_drone_capture_flag_fixedwingdrone.js'/*,
'gadget_erp5_page_drone_capture_flag_dronelogfollower.js'*/
'gadget_erp5_page_drone_capture_flag_fixedwingdrone.js',
'gadget_erp5_page_drone_capture_flag_enemydrone.js'
];
rJS(window)
......@@ -161,7 +152,8 @@
})
.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')
.push(function (form_gadget) {
return form_gadget.render({
......@@ -299,60 +291,38 @@
"hidden": 0,
"type": "FloatField"
},
"my_minimum_latitud": {
"my_map_size": {
"description": "",
"title": "Minimum latitude",
"default": min_lat,
"title": "Map size",
"default": MAP_SIZE,
"css_class": "",
"required": 1,
"editable": 1,
"key": "min_lat",
"key": "map_size",
"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": {
"my_start_AMSL": {
"description": "",
"title": "Minimum longitude",
"default": min_lon,
"title": "Start AMSL",
"default": start_AMSL,
"css_class": "",
"required": 1,
"editable": 1,
"key": "min_lon",
"key": "start_AMSL",
"hidden": 0,
"type": "FloatField"
},
"my_maximum_longitud": {
"description": "",
"title": "Maximum longitude",
"default": max_lon,
"my_map_seed": {
"description": "Seed value to randomize the map",
"title": "Seed value",
"default": url_seed ? url_seed : SEED,
"css_class": "",
"required": 1,
"editable": 1,
"key": "max_lon",
"key": "map_seed",
"hidden": 0,
"type": "FloatField"
},
"my_start_AMSL": {
"description": "",
"title": "Start AMSL",
"default": start_AMSL,
"css_class": "",
"required": 1,
"editable": 1,
"key": "start_AMSL",
"hidden": 0,
"type": "FloatField"
"type": "StringField"
},
"my_map_height": {
"description": "",
......@@ -365,39 +335,17 @@
"hidden": 0,
"type": "IntegerField"
},
"my_init_pos_lon": {
"description": "",
"title": "Initial drone longitude",
"default": INITIAL_POSITION.longitude,
"css_class": "",
"required": 1,
"editable": 1,
"key": "init_pos_lon",
"hidden": 0,
"type": "FloatField"
},
"my_init_pos_lat": {
/*"my_flag_weight": {
"description": "",
"title": "Initial drone latitude",
"default": INITIAL_POSITION.latitude,
"title": "Flag Weight",
"default": FLAG_WEIGHT,
"css_class": "",
"required": 1,
"editable": 1,
"key": "init_pos_lat",
"key": "flag_weight",
"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"
},
"type": "IntegerField"
},*/
"my_number_of_drones": {
"description": "",
"title": "Number of drones",
......@@ -432,13 +380,11 @@
group_list: [[
"left",
[["my_simulation_speed"], ["my_simulation_time"], ["my_number_of_drones"],
["my_minimum_latitud"], ["my_maximum_latitud"],
["my_minimum_longitud"], ["my_maximum_longitud"],
["my_init_pos_lat"], ["my_init_pos_lon"], ["my_init_pos_z"],
["my_map_height"]]
["my_map_size"], ["my_map_height"],// ["my_flag_weight"],
["my_start_AMSL"], ["my_map_seed"]]
], [
"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_roll"], ["my_drone_min_pitch"], ["my_drone_max_pitch"],
["my_drone_max_sink_rate"], ["my_drone_max_climb_rate"]]
......@@ -460,14 +406,119 @@
.declareJob('runGame', function runGame(options) {
var gadget = this, i,
fragment = gadget.element.querySelector('.simulator_div'),
game_parameters_json;
game_parameters_json, map_json;
DRONE_LIST = [];
fragment = domsugar(gadget.element.querySelector('.simulator_div'),
[domsugar('div')]).firstElementChild;
DRONE_LIST = [];
for (i = 0; i < options.number_of_drones; i += 1) {
DRONE_LIST[i] = {"id": i, "type": "FixedWingDroneAPI",
"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 = {
"drone": {
"maxAcceleration": parseInt(options.drone_max_acceleration, 10),
......@@ -487,24 +538,11 @@
"information": 0,
"communication": 0
},
"map": {
"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)
},
"map": randomizeMap(map_json),
"draw_flight_path": DRAW,
"temp_flight_path": true,
"log_drone_flight": LOG,
"log_interval_time": LOG_TIME,
"droneList": DRONE_LIST
"log_interval_time": LOG_TIME
};
return gadget.declareGadget("babylonjs.gadget.html",
{element: fragment, scope: 'simulator'})
......@@ -525,8 +563,7 @@
"type": "GadgetField",
"url": "babylonjs.gadget.html",
"sandbox": "public",
"renderjs_extra": '{"autorun": false, "width": ' + WIDTH + ', ' +
'"height": ' + HEIGHT + ', ' +
"renderjs_extra": '{"autorun": false, ' +
'"logic_file_list": ' + JSON.stringify(LOGIC_FILE_LIST) + ', ' +
'"game_parameters": ' + JSON.stringify(game_parameters_json) +
'}'
......@@ -553,35 +590,44 @@
return form_gadget.getContent();
})
.push(function (result) {
var a, blob, div, key, log, log_content;
var a, blob, div, key, log, log_content, aux;
i = 0;
for (key in result) {
if (result.hasOwnProperty(key)) {
log_content = result[key].join('\n').replaceAll(",", ";");
div = domsugar('div', { text: result.message });
document.querySelector('.container').parentNode.appendChild(div);
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'});
a = domsugar('a', {
text: 'Download Simulation LOG ' + i,
download: 'simulation_log_' + i
+ '_speed_' + game_parameters_json.drone.speed
+ '_min-speed_' + game_parameters_json.drone.minSpeed
+ '_max-speed_' + game_parameters_json.drone.maxSpeed
+ '_max-accel_' + game_parameters_json.drone.maxAcceleration
+ '_max-decel_' + game_parameters_json.drone.maxDeceleration
+ '_max-roll_' + game_parameters_json.drone.maxRoll
+ '_min-pitch_' + game_parameters_json.drone.minPitchAngle
+ '_max-pitch_' + game_parameters_json.drone.maxPitchAngle
+ '_max-sink_' + game_parameters_json.drone.maxSinkRate
+ '_max-climb_' + game_parameters_json.drone.maxClimbRate
+ '.txt',
download: 'simulation_log_' + i +
'_speed_' + game_parameters_json.drone.speed +
'_min-speed_' + game_parameters_json.drone.minSpeed +
'_max-speed_' + game_parameters_json.drone.maxSpeed +
'_max-accel_' + game_parameters_json.drone.maxAcceleration +
'_max-decel_' + game_parameters_json.drone.maxDeceleration +
'_max-roll_' + game_parameters_json.drone.maxRoll +
'_min-pitch_' + game_parameters_json.drone.minPitchAngle +
'_max-pitch_' + game_parameters_json.drone.maxPitchAngle +
'_max-sink_' + game_parameters_json.drone.maxSinkRate +
'_max-climb_' + game_parameters_json.drone.maxClimbRate +
'.txt',
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]);
a.dataset.downloadurl = ['text/plain', a.download,
a.href].join(':');
document.querySelector('.container').appendChild(div);
document.querySelector('.container').appendChild(log);
document.querySelector('.container').parentNode.appendChild(div);
document.querySelector('.container').parentNode.appendChild(log);
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) {
......@@ -590,4 +636,4 @@
});
});
}(window, rJS, domsugar, document, Blob));
\ No newline at end of file
}(window, rJS, domsugar, document, URLSearchParams, Blob));
\ No newline at end of file
......@@ -246,7 +246,7 @@
</item>
<item>
<key> <string>serial</string> </key>
<value> <string>1007.63299.40871.39799</string> </value>
<value> <string>1009.57725.14056.1911</string> </value>
</item>
<item>
<key> <string>state</string> </key>
......@@ -266,7 +266,7 @@
</tuple>
<state>
<tuple>
<float>1682437874.39</float>
<float>1689793877.59</float>
<string>UTC</string>
</tuple>
</state>
......
......@@ -16,7 +16,7 @@
</item>
<item>
<key> <string>height</string> </key>
<value> <int>512</int> </value>
<value> <int>1024</int> </value>
</item>
<item>
<key> <string>precondition</string> </key>
......@@ -28,7 +28,7 @@
</item>
<item>
<key> <string>width</string> </key>
<value> <int>512</int> </value>
<value> <int>1024</int> </value>
</item>
</dictionary>
</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