Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Permanent portal entities #437

Draft
wants to merge 40 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
2a64ff6
update portal marker instead of delete/create
le-jeu Feb 6, 2021
951148b
add PortalMarker class
le-jeu Feb 6, 2021
2f80172
small factor
le-jeu Feb 6, 2021
442ad3e
handle style inside portal class
le-jeu Feb 7, 2021
ac01aea
test if portal has details
le-jeu Feb 10, 2021
4e1eed0
use portal entity marker to get details
le-jeu Feb 10, 2021
cc90284
add details getter
le-jeu Feb 10, 2021
ffee660
merge data/details in a single object
le-jeu Feb 10, 2021
94fda6f
move portal marker hook
le-jeu Feb 10, 2021
69d4d8f
marker store selected
le-jeu Feb 10, 2021
6ae8eaf
handle portal location edit
le-jeu Feb 12, 2021
83acc21
move renderPortalDetails call to marker mechanism
le-jeu Feb 13, 2021
38c28c9
implement new portal data check in marker
le-jeu Feb 14, 2021
e329408
set marker style once
le-jeu Feb 14, 2021
ae46d7a
highlighter may return the applied style
le-jeu Feb 14, 2021
eae4ed6
add event name to portalSelected hook
le-jeu Feb 16, 2021
e8a144f
remove portalMarker.reset
le-jeu Feb 16, 2021
a24f110
render portal base on portal marker details
le-jeu Feb 16, 2021
68443e8
add portal health function
le-jeu Feb 16, 2021
fb4ef1e
use portal detail cache on new portal entities
le-jeu Feb 16, 2021
2bf85b0
remove obsolete data from portal details cache
le-jeu Feb 16, 2021
eb9344a
placeholder: use timestamp from link/field
le-jeu Feb 16, 2021
bcce300
fixup 97ed9a7fd46fab7bcd2a3f2234e75df7dbb05cc6
le-jeu Feb 17, 2021
b0f9a57
portalmarker: init select state
le-jeu Feb 17, 2021
9303425
render details on new selected portal entity
le-jeu Feb 17, 2021
c053363
fix: use this._details
le-jeu Feb 17, 2021
78e5ef0
better placeholder handling
le-jeu Feb 17, 2021
9c0bf28
render details: select if forced or not selected
le-jeu Feb 19, 2021
5e61254
handle missing history
le-jeu Feb 22, 2021
91215e2
keep portals attached to visible links/fields
le-jeu Feb 23, 2021
0840652
Revert "keep portals attached to visible links/fields"
le-jeu Feb 23, 2021
3066487
dont recreate markers when outside view
le-jeu Feb 23, 2021
1b13892
marker: update all data available
le-jeu May 6, 2021
009567c
portal edits change the timestamp
le-jeu May 22, 2021
f13ff25
apply to all placeholders
le-jeu Jul 5, 2021
3fda197
move portal style as statics of L.PortalMarker
le-jeu Jul 5, 2021
38bfdb7
portal location edit changes the timestamp
le-jeu Jul 6, 2021
e62410f
add comment #1
le-jeu Jun 7, 2021
8a4e4cf
fixup! placeholder: use timestamp from link/field
le-jeu Jun 7, 2021
cbd43a1
lint
le-jeu Jan 8, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
164 changes: 73 additions & 91 deletions core/code/map_data_render.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@ window.Render.prototype.clearPortalsOutsideBounds = function(bounds) {
var p = portals[guid];
// clear portals outside visible bounds - unless it's the selected portal, or it's relevant to artifacts
if (!bounds.contains(p.getLatLng()) && guid !== selectedPortal && !artifact.isInterestingPortal(guid)) {
this.deletePortalEntity(guid);
// remove the marker as a layer first
// deletion will be done at endRenderPass
p.remove();
count++;
}
}
Expand Down Expand Up @@ -170,11 +172,6 @@ window.Render.prototype.endRenderPass = function() {
this.bringPortalsToFront();

this.isRendering = false;

// re-select the selected portal, to re-render the side-bar. ensures that any data calculated from the map data is up to date
if (selectedPortal) {
renderPortalDetails (selectedPortal);
}
}

window.Render.prototype.bringPortalsToFront = function() {
Expand Down Expand Up @@ -248,17 +245,19 @@ window.Render.prototype.deleteFieldEntity = function(guid) {
}


window.Render.prototype.createPlaceholderPortalEntity = function(guid,latE6,lngE6,team) {
window.Render.prototype.createPlaceholderPortalEntity = function(guid,latE6,lngE6,team,timestamp) {
// intel no longer returns portals at anything but the closest zoom
// stock intel creates 'placeholder' portals from the data in links/fields - IITC needs to do the same
// we only have the portal guid, lat/lng coords, and the faction - no other data
// having the guid, at least, allows the portal details to be loaded once it's selected. however,
// no highlighters, portal level numbers, portal names, useful counts of portals, etc are possible

// zero will mean any other source of portal data will have a higher timestamp
timestamp = timestamp || 0;

var ent = [
guid, //ent[0] = guid
0, //ent[1] = timestamp - zero will mean any other source of portal data will have a higher timestamp
timestamp, //ent[1] = timestamp
//ent[2] = an array with the entity data
[ 'p', //0 - a portal
team, //1 - team
Expand All @@ -267,20 +266,9 @@ window.Render.prototype.createPlaceholderPortalEntity = function(guid,latE6,lngE
]
];

// placeholder portals don't have a useful timestamp value - so the standard code that checks for updated
// portal details doesn't apply
// so, check that the basic details are valid and delete the existing portal if out of date
if (guid in window.portals) {
var p = window.portals[guid];
if (team != p.options.data.team || latE6 != p.options.data.latE6 || lngE6 != p.options.data.lngE6) {
// team or location have changed - delete existing portal
this.deletePortalEntity(guid);
}
}

this.createPortalEntity(ent, 'core'); // placeholder

}
};


window.Render.prototype.createPortalEntity = function(ent, details) { // details expected in decodeArray.portal
Expand All @@ -289,119 +277,112 @@ window.Render.prototype.createPortalEntity = function(ent, details) { // details
var previousData = undefined;

var data = decodeArray.portal(ent[2], details);
var guid = ent[0];

// add missing fields
data.guid = guid;
if (!data.timestamp) {
data.timestamp = ent[1];
}

// LEGACY - TO BE REMOVED AT SOME POINT! use .guid, .timestamp and .data instead
data.ent = ent;

// check if entity already exists
if (ent[0] in window.portals) {
var oldPortal = guid in window.portals;

if (oldPortal) {
// yes. now check to see if the entity data we have is newer than that in place
var p = window.portals[ent[0]];
var p = window.portals[guid];

if (!data.history || p.options.data.history === data.history)
if (p.options.timestamp >= ent[1]) {
return; // this data is identical or older - abort processing
}
if (!p.willUpdate(data)) {
// this data doesn't bring new detail - abort processing
// re-add the portal to the relevant layer (does nothing if already in the correct layer)
// useful for portals outside the view
this.addPortalToMapLayer(p);
return p;
}

// the data we have is newer. many data changes require re-rendering of the portal
// (e.g. level changed, so size is different, or stats changed so highlighter is different)
// so to keep things simple we'll always re-create the entity in this case

// remember the old details, for the callback

previousData = p.options.data;

// preserve history
if (!data.history) {
data.history = previousData.history;
}

this.deletePortalEntity(ent[0]);
previousData = $.extend(true, {}, p.getDetails());
}

var portalLevel = parseInt(data.level)||0;
var team = teamStringToId(data.team);
// the data returns unclaimed portals as level 1 - but IITC wants them treated as level 0
if (team == TEAM_NONE) portalLevel = 0;

var latlng = L.latLng(data.latE6/1E6, data.lngE6/1E6);

var dataOptions = {
level: portalLevel,
team: team,
ent: ent, // LEGACY - TO BE REMOVED AT SOME POINT! use .guid, .timestamp and .data instead
guid: ent[0],
timestamp: ent[1],
data: data
};

window.pushPortalGuidPositionCache(ent[0], data.latE6, data.lngE6);

var marker = createMarker(latlng, dataOptions);

function handler_portal_click (e) {
window.renderPortalDetails(e.target.options.guid);
}
function handler_portal_dblclick (e) {
window.renderPortalDetails(e.target.options.guid);
window.map.setView(e.target.getLatLng(), DEFAULT_ZOOM);
}
function handler_portal_contextmenu (e) {
window.renderPortalDetails(e.target.options.guid);
if (window.isSmartphone()) {
window.show('info');
} else if (!$('#scrollwrapper').is(':visible')) {
$('#sidebartoggle').click();
}
}

marker.on('click', handler_portal_click);
marker.on('dblclick', handler_portal_dblclick);
marker.on('contextmenu', handler_portal_contextmenu);

window.runHooks('portalAdded', {portal: marker, previousData: previousData});

window.portals[ent[0]] = marker;
window.pushPortalGuidPositionCache(data.guid, data.latE6, data.lngE6);

// check for URL links to portal, and select it if this is the one
if (urlPortalLL && urlPortalLL[0] == marker.getLatLng().lat && urlPortalLL[1] == marker.getLatLng().lng) {
if (urlPortalLL && urlPortalLL[0] == latlng.lat && urlPortalLL[1] == latlng.lng) {
// URL-passed portal found via pll parameter - set the guid-based parameter
log.log('urlPortalLL '+urlPortalLL[0]+','+urlPortalLL[1]+' matches portal GUID '+ent[0]);
log.log('urlPortalLL '+urlPortalLL[0]+','+urlPortalLL[1]+' matches portal GUID '+data.guid);

urlPortal = ent[0];
urlPortal = data.guid;
urlPortalLL = undefined; // clear the URL parameter so it's not matched again
}
if (urlPortal == ent[0]) {
if (urlPortal === data.guid) {
// URL-passed portal found via guid parameter - set it as the selected portal
log.log('urlPortal GUID '+urlPortal+' found - selecting...');
selectedPortal = ent[0];
selectedPortal = data.guid;
urlPortal = undefined; // clear the URL parameter so it's not matched again
}

// (re-)select the portal, to refresh the sidebar on any changes
if (ent[0] == selectedPortal) {
log.log('portal guid '+ent[0]+' is the selected portal - re-rendering portal details');
renderPortalDetails (selectedPortal);
var marker = undefined;
if (oldPortal) {
// update marker style/highlight and layer
marker = window.portals[data.guid];

marker.updateDetails(data);

window.runHooks('portalAdded', {portal: marker, previousData: previousData});
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the hook is misleading now since the marker is the same marker. Only the data changed.
In this case, we are closer to the portalDetailLoaded but with eventually no details (i.e. from core to summary/extended)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the hook is misleading

But that was expected, that's why previousData provided. I suppose we should leave it as it.
May be we should add some property to denote placeholders.

But we can revise that from scratch when implementing #217.

} else {
marker = createMarker(latlng, data);

// in case of incomplete data while having fresh details in cache, update the portal with those details
if (portalDetail.isFresh(guid)) {
var oldDetails = portalDetail.get(guid);
if (data.timestamp > oldDetails.timestamp) {
// data is more recent than the cached details so we remove them from the cache
portalDetail.remove(guid);
} else if (marker.willUpdate(oldDetails)) {
marker.updateDetails(oldDetails);
}
}

window.runHooks('portalAdded', {portal: marker});

window.portals[data.guid] = marker;

if (selectedPortal === data.guid) {
marker.renderDetails();
}
}

window.ornaments.addPortal(marker);

//TODO? postpone adding to the map layer
// TODO? postpone adding to the map layer
this.addPortalToMapLayer(marker);

}
return marker;
};


window.Render.prototype.createFieldEntity = function(ent) {
this.seenFieldsGuid[ent[0]] = true; // flag we've seen it

var data = {
// type: ent[2][0],
timestamp: ent[1],
team: ent[2][1],
points: ent[2][2].map(function(arr) { return {guid: arr[0], latE6: arr[1], lngE6: arr[2] }; })
};

//create placeholder portals for field corners. we already do links, but there are the odd case where this is useful
for (var i=0; i<3; i++) {
var p=data.points[i];
this.createPlaceholderPortalEntity(p.guid, p.latE6, p.lngE6, data.team);
this.createPlaceholderPortalEntity(p.guid, p.latE6, p.lngE6, data.team, 0);
}

// check if entity already exists
Expand Down Expand Up @@ -458,6 +439,7 @@ window.Render.prototype.createLinkEntity = function(ent,faked) {

var data = { // TODO add other properties and check correction direction
// type: ent[2][0],
timestamp: ent[1],
team: ent[2][1],
oGuid: ent[2][2],
oLatE6: ent[2][3],
Expand All @@ -468,8 +450,8 @@ window.Render.prototype.createLinkEntity = function(ent,faked) {
};

// create placeholder entities for link start and end points (before checking if the link itself already exists
this.createPlaceholderPortalEntity(data.oGuid, data.oLatE6, data.oLngE6, data.team);
this.createPlaceholderPortalEntity(data.dGuid, data.dLatE6, data.dLngE6, data.team);
this.createPlaceholderPortalEntity(data.oGuid, data.oLatE6, data.oLngE6, data.team, data.timestamp);
this.createPlaceholderPortalEntity(data.dGuid, data.dLatE6, data.dLngE6, data.team, data.timestamp);


// check if entity already exists
Expand Down
9 changes: 0 additions & 9 deletions core/code/map_data_request.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,15 +69,6 @@ window.MapDataRequest = function() {

// ensure we have some initial map status
this.setStatus ('startup', undefined, -1);

// add a portalDetailLoaded hook, so we can use the extended details to update portals on the map
var _this = this;
addHook('portalDetailLoaded', function(data){
if(data.success) {
_this.render.createPortalEntity(data.ent, 'detailed');
}
});

}


Expand Down
21 changes: 8 additions & 13 deletions core/code/portal_detail.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,29 +25,24 @@ window.portalDetail.isFresh = function(guid) {
return cache.isFresh(guid);
}

window.portalDetail.remove = function(guid) {
return cache.remove(guid);
}

var handleResponse = function(deferred, guid, data, success) {
if (!data || data.error || !data.result) {
success = false;
}

if (success) {

var dict = decodeArray.portal(data.result, 'detailed');

// entity format, as used in map data
var ent = [guid,dict.timestamp,data.result];
var ent = [guid,data.result[13],data.result];
var portal = window.mapDataRequest.render.createPortalEntity(ent, 'detailed');

cache.store(guid,dict);

//FIXME..? better way of handling sidebar refreshing...

if (guid == selectedPortal) {
renderPortalDetails(guid);
}
cache.store(guid,portal.options.data);

deferred.resolve(dict);
window.runHooks ('portalDetailLoaded', {guid:guid, success:success, details:dict, ent:ent});
deferred.resolve(portal.options.data);
window.runHooks ('portalDetailLoaded', {guid:guid, success:success, details:portal.options.data, ent:ent});

} else {
if (data && data.error == "RETRY") {
Expand Down
Loading