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

Flush aura cache when tokens with auras are changed #4058

Merged
Changes from all commits
Commits
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
138 changes: 69 additions & 69 deletions src/main/java/net/rptools/maptool/client/ui/zone/ZoneView.java
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,10 @@ private record IlluminationKey(double multiplier) {}

// region These fields track light sources and their illuminated areas.

/** Map light source type to all tokens with that type. */
/**
* Map light source type to all tokens with that type. Will always have entries for each light
* type, so no need to check whether they exist.
*/
private final Map<LightSource.Type, Set<GUID>> lightSourceMap = new HashMap<>();

// endregion
Expand Down Expand Up @@ -135,6 +138,10 @@ private record IlluminationKey(double multiplier) {}
*/
public ZoneView(Zone zone) {
this.zone = zone;

for (final var type : LightSource.Type.values()) {
lightSourceMap.put(type, new HashSet<>());
}
findLightSources();

new MapToolEventBus().getMainEventBus().register(this);
Expand Down Expand Up @@ -265,9 +272,7 @@ private IlluminationModel getIlluminationModel(IlluminationKey illuminationKey)

// We need to get all lights ordered by lumens. From there, we can do darkness subtraction and
// build drawable lights for each, and then build a lumens map.
final var lightSourceTokenGuids =
new ArrayList<>(
lightSourceMap.getOrDefault(LightSource.Type.NORMAL, Collections.emptySet()));
final var lightSourceTokenGuids = lightSourceMap.get(LightSource.Type.NORMAL);
final var lightSourceTokens =
lightSourceTokenGuids.stream()
.map(zone::getToken)
Expand Down Expand Up @@ -493,9 +498,7 @@ private Illumination getIllumination(IlluminationKey illuminationKey) {
}

if (token.hasLightSources()
&& !lightSourceMap
.getOrDefault(LightSource.Type.NORMAL, Collections.emptySet())
.contains(token.getId())) {
&& !lightSourceMap.get(LightSource.Type.NORMAL).contains(token.getId())) {
// This accounts for temporary tokens (such as during an Expose Last Path)
personalLights.addAll(calculateLitAreas(token, sight.getMultiplier()));
}
Expand Down Expand Up @@ -642,62 +645,59 @@ public Area getVisibleArea(Token token, PlayerView view) {
public List<DrawableLight> getDrawableAuras() {
if (drawableAuras == null) {
List<DrawableLight> lightList = new LinkedList<DrawableLight>();
final var auraTokenGUIDs = lightSourceMap.get(LightSource.Type.AURA);
if (auraTokenGUIDs != null) {
for (GUID lightSourceToken : auraTokenGUIDs) {
Token token = zone.getToken(lightSourceToken);
if (token == null) {
for (GUID lightSourceToken : lightSourceMap.get(LightSource.Type.AURA)) {
Token token = zone.getToken(lightSourceToken);
if (token == null) {
continue;
}
Point p = FogUtil.calculateVisionCenter(token, zone);

for (AttachedLightSource als : token.getLightSources()) {
LightSource lightSource = MapTool.getCampaign().getLightSource(als.getLightSourceId());
if (lightSource == null) {
continue;
}
// Token can also have non-auras lights, we don't want those.
if (lightSource.getType() != LightSource.Type.AURA) {
continue;
}
Point p = FogUtil.calculateVisionCenter(token, zone);

for (AttachedLightSource als : token.getLightSources()) {
LightSource lightSource = MapTool.getCampaign().getLightSource(als.getLightSourceId());
if (lightSource == null) {
Area lightSourceArea = lightSource.getArea(token, zone);
lightSourceArea.transform(AffineTransform.getTranslateInstance(p.x, p.y));
Area visibleArea =
FogUtil.calculateVisibility(
p,
lightSourceArea,
getTopologyTree(Zone.TopologyType.WALL_VBL),
getTopologyTree(Zone.TopologyType.HILL_VBL),
getTopologyTree(Zone.TopologyType.PIT_VBL));

// This needs to be cached somehow
for (Light light : lightSource.getLightList()) {
// If there is no paint, it's a "bright aura" that just shows whatever is beneath it
// and doesn't need to be rendered.
if (light.getPaint() == null) {
continue;
}
// Token can also have non-auras lights, we don't want those.
if (lightSource.getType() != LightSource.Type.AURA) {
boolean isOwner = token.getOwners().contains(MapTool.getPlayer().getName());
if ((light.isGM() && !MapTool.getPlayer().isEffectiveGM())) {
continue;
}

Area lightSourceArea = lightSource.getArea(token, zone);
lightSourceArea.transform(AffineTransform.getTranslateInstance(p.x, p.y));
Area visibleArea =
FogUtil.calculateVisibility(
p,
lightSourceArea,
getTopologyTree(Zone.TopologyType.WALL_VBL),
getTopologyTree(Zone.TopologyType.HILL_VBL),
getTopologyTree(Zone.TopologyType.PIT_VBL));

// This needs to be cached somehow
for (Light light : lightSource.getLightList()) {
// If there is no paint, it's a "bright aura" that just shows whatever is beneath it
// and doesn't need to be rendered.
if (light.getPaint() == null) {
continue;
}
boolean isOwner = token.getOwners().contains(MapTool.getPlayer().getName());
if ((light.isGM() && !MapTool.getPlayer().isEffectiveGM())) {
continue;
}
if ((!token.isVisible()) && !MapTool.getPlayer().isEffectiveGM()) {
continue;
}
if (token.isVisibleOnlyToOwner() && !AppUtil.playerOwns(token)) {
continue;
}
if (light.isOwnerOnly() && !isOwner && !MapTool.getPlayer().isEffectiveGM()) {
continue;
}

// Calculate the area covered by this particular range.
Area lightArea = lightSource.getArea(token, zone, light);
lightArea.transform(AffineTransform.getTranslateInstance(p.x, p.y));
lightArea.intersect(visibleArea);
lightList.add(new DrawableLight(light.getPaint(), lightArea, light.getLumens()));
if ((!token.isVisible()) && !MapTool.getPlayer().isEffectiveGM()) {
continue;
}
if (token.isVisibleOnlyToOwner() && !AppUtil.playerOwns(token)) {
continue;
}
if (light.isOwnerOnly() && !isOwner && !MapTool.getPlayer().isEffectiveGM()) {
continue;
}

// Calculate the area covered by this particular range.
Area lightArea = lightSource.getArea(token, zone, light);
lightArea.transform(AffineTransform.getTranslateInstance(p.x, p.y));
lightArea.intersect(visibleArea);
lightList.add(new DrawableLight(light.getPaint(), lightArea, light.getLumens()));
}
}
}
Expand All @@ -712,7 +712,9 @@ public List<DrawableLight> getDrawableAuras() {
* Find the light sources from all appropriate tokens, and store them in {@link #lightSourceMap}.
*/
private void findLightSources() {
lightSourceMap.clear();
for (final var set : lightSourceMap.values()) {
set.clear();
}

for (Token token : zone.getAllTokens()) {
if (token.hasLightSources() && token.isVisible()) {
Expand All @@ -722,9 +724,7 @@ private void findLightSources() {
if (lightSource == null) {
continue;
}
Set<GUID> lightSet =
lightSourceMap.computeIfAbsent(lightSource.getType(), k -> new HashSet<>());
lightSet.add(token.getId());
lightSourceMap.get(lightSource.getType()).add(token.getId());
}
}
}
Expand Down Expand Up @@ -832,14 +832,19 @@ public void flush(Token token) {
visibleAreaMap.clear();
// TODO Could we instead only clear those views that include the token?
drawableLights.clear();
drawableAuras = null;
} else if (token.getHasSight()) {
contributedPersonalLightsByToken.remove(token.getId());
// TODO Could we instead only clear those views that include the token?
illuminationsPerView.clear();
exposedAreaMap.clear();
visibleAreaMap.clear();
drawableLights.clear();
}

// If the token had auras as well, we'll need to recompute them. This could be more precise
// (i.e., only do the ones for this token) but that's more complicated than it's worth for now.
if (lightSourceMap.get(LightSource.Type.AURA).contains(token.getId())
|| token.hasLightSourceType(LightSource.Type.AURA)) {
drawableAuras = null;
}
}
Expand Down Expand Up @@ -900,10 +905,7 @@ private void onTokensRemoved(TokensRemoved event) {
if (lightSource == null) {
continue;
}
Set<GUID> lightSet = lightSourceMap.get(lightSource.getType());
if (lightSet != null) {
lightSet.remove(token.getId());
}
lightSourceMap.get(lightSource.getType()).remove(token.getId());
}
}

Expand Down Expand Up @@ -958,12 +960,10 @@ private boolean processTokenAddChangeEvent(List<Token> tokens) {
if (lightSource != null) {
Set<GUID> lightSet = lightSourceMap.get(lightSource.getType());
if (hasLightSource) {
if (lightSet == null) {
lightSet = new HashSet<GUID>();
lightSourceMap.put(lightSource.getType(), lightSet);
}
lightSet.add(token.getId());
} else if (lightSet != null) lightSet.remove(token.getId());
} else {
lightSet.remove(token.getId());
}
}
}
hasSight |= token.getHasSight();
Expand Down