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

Make ownership checks consistent between All Players and explicit assignment #4404

Merged
Merged
Show file tree
Hide file tree
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
12 changes: 1 addition & 11 deletions src/main/java/net/rptools/maptool/client/AppUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.security.CodeSource;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
Expand Down Expand Up @@ -322,16 +321,7 @@ public static boolean playerOwns(Token token) {
* @return true if owned by all, or one of the owners is online and not a gm.
*/
public static boolean ownedByOnePlayer(Token token) {
if (token.isOwnedByAll()) {
return true;
}
List<String> players = MapTool.getNonGMs();
for (String owner : token.getOwners()) {
if (players.contains(owner)) {
return true;
}
}
return false;
return token.isOwnedByAny(MapTool.getNonGMs());
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ public boolean matchToken(Token t) {
if (ownership == Ownership.NONE) return (!t.hasOwners());
if (ownership == Ownership.MULTIPLE) return (t.isOwnedByAll() || t.getOwners().size() > 1);
if (ownership == Ownership.SINGLE) return (!t.isOwnedByAll() && t.getOwners().size() == 1);
if (ownership == Ownership.ARRAY) return (!Collections.disjoint(t.getOwners(), ownerList));
if (ownership == Ownership.ARRAY) return (t.isOwnedByAny(ownerList));

boolean isOwner = t.isOwner(playerName);
if (ownership == Ownership.SELF) return (isOwner);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1337,11 +1337,10 @@ private String getPropertyNames(Token token, String delim, String pattern, boole
* @return a string list of the token owners.
*/
public String getOwners(Token token, String delim) {
String[] owners = new String[token.getOwners().size()];
token.getOwners().toArray(owners);
var owners = new ArrayList<>(token.getOwners());
if ("json".endsWith(delim)) {
JsonArray jarr = new JsonArray();
Arrays.stream(owners).forEach(o -> jarr.add(new JsonPrimitive(o)));
owners.forEach(o -> jarr.add(new JsonPrimitive(o)));
return jarr.toString();
} else {
return StringFunctions.getInstance().join(owners, delim);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -833,15 +833,7 @@ public boolean commit() {
// If we are not a GM and the only non GM owner make sure we can't
// take our selves off of the owners list
if (!MapTool.getPlayer().isGM()) {
boolean hasPlayer = false;
Set<String> owners = token.getOwners();
if (owners != null) {
for (Player pl : MapTool.getPlayerList()) {
if (!pl.isGM() && owners.contains(pl.getName())) {
hasPlayer = true;
}
}
}
boolean hasPlayer = token.isOwnedByAny(MapTool.getNonGMs());
if (!hasPlayer) {
token.addOwner(MapTool.getPlayer().getName());
}
Expand Down
15 changes: 8 additions & 7 deletions src/main/java/net/rptools/maptool/client/ui/zone/ZoneView.java
Original file line number Diff line number Diff line change
Expand Up @@ -650,6 +650,14 @@ public List<DrawableLight> getDrawableAuras() {
if (token == null) {
continue;
}
if (!token.isVisible() && !MapTool.getPlayer().isEffectiveGM()) {
continue;
}
if (token.isVisibleOnlyToOwner() && !AppUtil.playerOwns(token)) {
continue;
}
boolean isOwner = token.isOwner(MapTool.getPlayer().getName());

Point p = FogUtil.calculateVisionCenter(token, zone);

for (AttachedLightSource als : token.getLightSources()) {
Expand Down Expand Up @@ -680,16 +688,9 @@ public List<DrawableLight> getDrawableAuras() {
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;
}
Expand Down
39 changes: 38 additions & 1 deletion src/main/java/net/rptools/maptool/model/Token.java
Original file line number Diff line number Diff line change
Expand Up @@ -1109,8 +1109,45 @@ public synchronized void clearAllOwners() {
ownerList.clear();
}

/**
* Check if the token is owned by the provided player.
*
* <p>This method allows implicit ownership when the token is owned by all players.
*
* @param playerId The player name to check ownership against.
* @return {@code true} if {@code playerId} identifies an owner of the token.
*/
public synchronized boolean isOwner(String playerId) {
return (ownerType == OWNER_TYPE_ALL || ownerList.contains(playerId));
return ownerType == OWNER_TYPE_ALL || ownerList.contains(playerId);
}

/**
* Checks if the token is owned by any of the provided players.
*
* <p>This method allows implicit ownership when the token is owned by all players. It is as if
* each player was checked individually via {@link #isOwner(String)}, but more convenient and
* efficient.
*
* @param playerIds The player names to check ownership against.
* @return {@code true} if there is a player in {@code playerIds} that is an owner of this token.
*/
public synchronized boolean isOwnedByAny(Collection<String> playerIds) {
if (playerIds.isEmpty()) {
return false;
}

return ownerType == OWNER_TYPE_ALL || !Collections.disjoint(ownerList, playerIds);
}

/**
* Checks if the token is not owned by anyone.
*
* <p>If the token is owned by all players, this will return {@code false}
*
* @return {@code true} if the token has any owners.
*/
public synchronized boolean isOwnedByNone() {
return ownerType != OWNER_TYPE_ALL && ownerList.isEmpty();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,7 @@ public CompletableFuture<Optional<MTScriptMacroInfo>> getMTScriptMacroInfo(Strin
new MTScriptMacroInfo(
macroName,
buttonProps.getCommand(),
library.getOwners().size() == 0 || !buttonProps.getAllowPlayerEdits(),
library.isOwnedByNone() || !buttonProps.getAllowPlayerEdits(),
!buttonProps.getAllowPlayerEdits() && buttonProps.getAutoExecute(),
buttonProps.getEvaluatedToolTip()));
});
Expand Down
39 changes: 8 additions & 31 deletions src/main/java/net/rptools/maptool/util/EventMacroUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,25 +25,13 @@
import net.rptools.maptool.model.TextMessage;
import net.rptools.maptool.model.Token;
import net.rptools.maptool.model.library.LibraryManager;
import net.rptools.maptool.model.player.Player;
import net.rptools.parser.ParserException;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

/** Utility class to facilitate macro events like onTokenMove and onInitiativeChange. */
public class EventMacroUtil {
private static final Logger LOGGER = LogManager.getLogger(EventMacroUtil.class);
/**
* Scans all maps to find the first Lib:Token containing a macro that matches the given "callback"
* string. If more than one token has such a macro, the first one encountered is returned -
* because this order is unpredictable, this is very much not encouraged.
*
* @param macroCallback the macro name to find
* @return the first Lib:token found that contains the requested macro, or null if none
*/
public static Token getEventMacroToken(final String macroCallback) {
return getEventMacroTokens(macroCallback).stream().findFirst().orElse(null);
}

/**
* Scans all maps to find any Lib:Tokens that contain a macro matching the given "callback" label.
Expand All @@ -57,27 +45,16 @@ public static List<Token> getEventMacroTokens(final String macroCallback) {
for (ZoneRenderer zr : zrenderers) {
List<Token> tokenList =
zr.getZone().getTokensFiltered(t -> t.getName().toLowerCase().startsWith("lib:"));
var nonGms = MapTool.getNonGMs();
for (Token token : tokenList) {
// If the token is not owned by everyone and all owners are GMs
// then we are in
// If the token is not owned by everyone and all owners are GMs then we are in
// its a trusted Lib:token so we can run the macro
if (token != null) {
if (token.isOwnedByAll()) {
continue;
} else {
Set<String> gmPlayers = new HashSet<String>();
for (Object o : MapTool.getPlayerList()) {
Player p = (Player) o;
if (p.isGM()) {
gmPlayers.add(p.getName());
}
}
for (String owner : token.getOwners()) {
if (!gmPlayers.contains(owner)) {
continue;
}
}
}
if (token.isOwnedByAll()) {
continue;
}
if (token.isOwnedByAny(nonGms)) {
// Not trusted, don't run.
continue;
}
if (token.getMacro(macroCallback, false) != null) {
found.add(token);
Expand Down
Loading