feat: add the ability to have multiple values for a tag

This commit is contained in:
Sekwah 2023-11-29 03:18:25 +00:00
parent 394b238958
commit 0753839699
11 changed files with 220 additions and 100 deletions

View File

@ -6,7 +6,10 @@ Also I will set up release please to work with the below types for pretty change
The re-code is based off a mix of the original version, and the original re-code that was abandoned [see here](https://github.com/sekwah41/Advanced-Portals/tree/recode/src/main/java/com/sekwah/advancedportals).
There were no issues with this approach, though for a number of reasons outside of the codebase progress was not made fast enough.
Part of this are currently a mess in terms of package organising, though any API changes will be documented in the changelog as well as the main registry classes should be relatively solid.
The goal of this rewrite is to make it easier to port to other platforms as well as add extra tags.
# Contributing
Please ensure that your commits are in the following style for PR's

View File

@ -36,7 +36,14 @@ public class CreatePortalSubCommand implements SubCommand {
sender.sendMessage(Lang.translate("command.create.tags"));
sender.sendMessage("\u00A7a" + "triggerBlock\u00A77:\u00A7e" + Arrays.toString(portal.getTriggerBlocks()));
for (DataTag tag: portal.getArgs()) {
sender.sendMessage("\u00A7a" + tag.NAME + "\u00A77:\u00A7e" + tag.VALUE);
if(tag.VALUES.length == 1) {
sender.sendMessage("\u00A7a" + tag.NAME + "\u00A77:\u00A7e" + tag.VALUES[0]);
} else {
// Output in the format tag.NAME(index): value
for (int i = 0; i < tag.VALUES.length; i++) {
sender.sendMessage("\u00A7a" + tag.NAME + "(" + i + ")\u00A77:\u00A7e" + tag.VALUES[i]);
}
}
}
}
sender.sendMessage(Lang.translate("messageprefix.negative") + Lang.translate("command.create.error"));
@ -53,6 +60,7 @@ public class CreatePortalSubCommand implements SubCommand {
@Override
public List<String> onTabComplete(CommandSenderContainer sender, String[] args) {
// TODO add tab complete for tags
return null;
}

View File

@ -3,11 +3,12 @@ package com.sekwah.advancedportals.core.destination;
import com.google.gson.annotations.SerializedName;
import com.google.inject.Inject;
import com.sekwah.advancedportals.core.connector.containers.PlayerContainer;
import com.sekwah.advancedportals.core.registry.TagTarget;
import com.sekwah.advancedportals.core.serializeddata.DataTag;
import com.sekwah.advancedportals.core.serializeddata.PlayerLocation;
import com.sekwah.advancedportals.core.registry.TagRegistry;
import com.sekwah.advancedportals.core.warphandler.ActivationData;
import com.sekwah.advancedportals.core.warphandler.TagHandler;
import com.sekwah.advancedportals.core.warphandler.Tag;
import java.util.ArrayList;
import java.util.HashMap;
@ -23,7 +24,7 @@ import java.util.Set;
*
* @author sekwah41
*/
public class Destination {
public class Destination implements TagTarget {
@Inject
TagRegistry<Destination> tagRegistry;
@ -32,7 +33,7 @@ public class Destination {
private PlayerLocation loc;
@SerializedName("a")
private HashMap<String, String> args = new HashMap<>();
private HashMap<String, String[]> args = new HashMap<>();
private transient Set<String> argsCol;
@ -40,16 +41,23 @@ public class Destination {
this.loc = loc;
}
public String getArg(String argName) {
@Override
public String[] getArgValues(String argName) {
return this.args.get(argName);
}
public void setArg(String argName, String argValue) {
@Override
public void setArgValues(String argName, String[] argValue) {
this.args.put(argName, argValue);
}
public void setArg(DataTag portalTag) {
this.setArg(portalTag.NAME, portalTag.VALUE);
@Override
public void addArg(String argName, String argValues) {
}
public void setArgValues(DataTag portalTag) {
this.setArgValues(portalTag.NAME, portalTag.VALUES);
}
public void removeArg(String arg) {
@ -66,19 +74,19 @@ public class Destination {
public boolean portalActivate(PlayerContainer player, ActivationData data) {
DataTag[] destiTags = new DataTag[args.size()];
int i = 0;
for(Map.Entry<String, String> entry : args.entrySet()) {
for(Map.Entry<String, String[]> entry : args.entrySet()) {
destiTags[i++] = new DataTag(entry.getKey(), entry.getValue());
}
for(DataTag destiTag : destiTags) {
TagHandler.Activation<Destination> activationHandler = tagRegistry.getActivationHandler(destiTag.NAME);
Tag.Activation activationHandler = tagRegistry.getActivationHandler(destiTag.NAME);
if(activationHandler != null) {
activationHandler.preActivated(this, player, data, this.getArg(destiTag.NAME));
activationHandler.preActivated(this, player, data, this.getArgValues(destiTag.NAME));
}
}
for(DataTag destiTag : destiTags) {
TagHandler.Activation<Destination> activationHandler = tagRegistry.getActivationHandler(destiTag.NAME);
Tag.Activation activationHandler = tagRegistry.getActivationHandler(destiTag.NAME);
if(activationHandler != null) {
activationHandler.activated(this, player, data, this.getArg(destiTag.NAME));
activationHandler.activated(this, player, data, this.getArgValues(destiTag.NAME));
}
}
return true;
@ -87,20 +95,20 @@ public class Destination {
public void postActivate(PlayerContainer player, ActivationData data) {
DataTag[] destiTags = new DataTag[args.size()];
int i = 0;
for(Map.Entry<String, String> entry : args.entrySet()) {
for(Map.Entry<String, String[]> entry : args.entrySet()) {
destiTags[i++] = new DataTag(entry.getKey(), entry.getValue());
}
for(DataTag destiTag : destiTags) {
TagHandler.Activation<Destination> activationHandler = tagRegistry.getActivationHandler(destiTag.NAME);
Tag.Activation activationHandler = tagRegistry.getActivationHandler(destiTag.NAME);
if(activationHandler != null) {
activationHandler.postActivated(this, player, data, this.getArg(destiTag.NAME));
activationHandler.postActivated(this, player, data, this.getArgValues(destiTag.NAME));
}
}
}
public ArrayList<DataTag> getArgs() {
ArrayList<DataTag> tagList = new ArrayList<>();
for(Map.Entry<String, String> entry : this.args.entrySet()){
for(Map.Entry<String, String[]> entry : this.args.entrySet()){
tagList.add(new DataTag(entry.getKey(), entry.getValue()));
}
return tagList;

View File

@ -3,11 +3,12 @@ package com.sekwah.advancedportals.core.portal;
import com.google.gson.annotations.SerializedName;
import com.google.inject.Inject;
import com.sekwah.advancedportals.core.connector.containers.PlayerContainer;
import com.sekwah.advancedportals.core.registry.TagTarget;
import com.sekwah.advancedportals.core.serializeddata.DataTag;
import com.sekwah.advancedportals.core.serializeddata.WorldLocation;
import com.sekwah.advancedportals.core.registry.TagRegistry;
import com.sekwah.advancedportals.core.warphandler.ActivationData;
import com.sekwah.advancedportals.core.warphandler.TagHandler;
import com.sekwah.advancedportals.core.warphandler.Tag;
import java.util.ArrayList;
import java.util.HashMap;
@ -16,10 +17,10 @@ import java.util.Map;
/**
* @author sekwah41
*/
public class AdvancedPortal {
public class AdvancedPortal implements TagTarget {
@Inject
TagRegistry<AdvancedPortal> tagRegistry;
transient TagRegistry<AdvancedPortal> tagRegistry;
@SerializedName("max")
private WorldLocation maxLoc;
@ -31,7 +32,7 @@ public class AdvancedPortal {
private String[] triggerBlocks = {"PORTAL"};
@SerializedName("a")
private HashMap<String, String> args = new HashMap<>();
private HashMap<String, String[]> args = new HashMap<>();
public AdvancedPortal(WorldLocation maxLoc, WorldLocation minLoc) {
this.maxLoc = maxLoc;
@ -46,14 +47,22 @@ public class AdvancedPortal {
return this.minLoc;
}
public String getArg(String argName) {
@Override
public String[] getArgValues(String argName) {
return this.args.get(argName);
}
public void setArg(String argName, String argValue) {
this.args.put(argName, argValue);
@Override
public void setArgValues(String argName, String[] argValues) {
this.args.put(argName, argValues);
}
@Override
public void addArg(String argName, String argValues) {
}
@Override
public void removeArg(String arg) {
this.args.remove(arg);
}
@ -71,38 +80,38 @@ public class AdvancedPortal {
ActivationData data = new ActivationData();
DataTag[] portalTags = new DataTag[args.size()];
int i = 0;
for(Map.Entry<String, String> entry : args.entrySet()) {
for(Map.Entry<String, String[]> entry : args.entrySet()) {
portalTags[i++] = new DataTag(entry.getKey(), entry.getValue());
}
for(DataTag portalTag : portalTags) {
TagHandler.Activation<AdvancedPortal> activationHandler = tagRegistry.getActivationHandler(portalTag.NAME);
Tag.Activation activationHandler = tagRegistry.getActivationHandler(portalTag.NAME);
if(activationHandler != null) {
activationHandler.preActivated(this, player, data, this.getArg(portalTag.NAME));
activationHandler.preActivated(this, player, data, this.getArgValues(portalTag.NAME));
}
}
for(DataTag portalTag : portalTags) {
TagHandler.Activation<AdvancedPortal> activationHandler = tagRegistry.getActivationHandler(portalTag.NAME);
Tag.Activation activationHandler = tagRegistry.getActivationHandler(portalTag.NAME);
if(activationHandler != null) {
activationHandler.activated(this, player, data, this.getArg(portalTag.NAME));
activationHandler.activated(this, player, data, this.getArgValues(portalTag.NAME));
}
}
for(DataTag portalTag : portalTags) {
TagHandler.Activation<AdvancedPortal> activationHandler = tagRegistry.getActivationHandler(portalTag.NAME);
Tag.Activation activationHandler = tagRegistry.getActivationHandler(portalTag.NAME);
if(activationHandler != null) {
activationHandler.postActivated(this, player, data, this.getArg(portalTag.NAME));
activationHandler.postActivated(this, player, data, this.getArgValues(portalTag.NAME));
}
}
return true;
}
public void setArg(DataTag portalTag) {
this.setArg(portalTag.NAME, portalTag.VALUE);
public void setArgValues(DataTag portalTag) {
this.setArgValues(portalTag.NAME, portalTag.VALUES);
}
public ArrayList<DataTag> getArgs() {
ArrayList<DataTag> tagList = new ArrayList<>();
for(Map.Entry<String, String> entry : this.args.entrySet()){
for(Map.Entry<String, String[]> entry : this.args.entrySet()){
tagList.add(new DataTag(entry.getKey(), entry.getValue()));
}
return tagList;

View File

@ -2,7 +2,8 @@ package com.sekwah.advancedportals.core.registry;
import com.google.inject.Inject;
import com.sekwah.advancedportals.core.AdvancedPortalsCore;
import com.sekwah.advancedportals.core.warphandler.TagHandler;
import com.sekwah.advancedportals.core.portal.AdvancedPortal;
import com.sekwah.advancedportals.core.warphandler.Tag;
import java.util.ArrayList;
import java.util.Collections;
@ -25,19 +26,21 @@ public class TagRegistry<T> {
*/
private ArrayList<String> tags = new ArrayList();
/**
* Description of tags for help commands
* Description of tags for help commands (will try to use translation strings before rendering
* Possibly add a way to allow addons to supply extra info to the Lang class in the future.
*/
private Map<String, String> tagDesc = new HashMap();
private Map<String, TagHandler.Activation<T>> activationHandlers = new HashMap();
private Map<String, TagHandler.Creation<T>> creationHandlers = new HashMap();
private Map<String, TagHandler.TagStatus<T>> statusHandlers = new HashMap();
private Map<String, Tag.Activation> activationHandlers = new HashMap();
private Map<String, Tag.Creation> creationHandlers = new HashMap();
private Map<String, Tag.TagStatus> statusHandlers = new HashMap();
/**
* Portals to trigger when a portal is activated
*
* @param arg
* @return
*/
public TagHandler.Activation<T> getActivationHandler(String arg) {
public Tag.Activation getActivationHandler(String arg) {
return this.activationHandlers.get(arg);
}
@ -46,7 +49,7 @@ public class TagRegistry<T> {
* @param arg
* @return
*/
public TagHandler.Creation<T> getCreationHandler(String arg) {
public Tag.Creation getCreationHandler(String arg) {
return this.creationHandlers.get(arg);
}
@ -55,24 +58,10 @@ public class TagRegistry<T> {
* @param arg
* @return
*/
public TagHandler.TagStatus<T> getTagStatusHandler(String arg) {
public Tag.TagStatus getTagStatusHandler(String arg) {
return this.statusHandlers.get(arg);
}
/**
*
* @param tag
* @param desc
* @param tagHandler
* @return if the tag was registered
*/
public boolean registerTag(String tag, String desc, TagHandler tagHandler) {
if (registerTag(tag, tagHandler)) {
this.tagDesc.put(tag, desc);
}
return false;
}
/**
* It is reccomended that you use the taghandlers to add tag functionality. However
@ -81,7 +70,7 @@ public class TagRegistry<T> {
* @param tag
* @return if the tag was registered
*/
public boolean registerTag(String tag) {
private boolean registerTag(String tag) {
if (tag.contains(" ")) {
this.portalsCore.getInfoLogger().logWarning("The tag '"
+ tag + "' is invalid as it contains spaces.");
@ -97,14 +86,7 @@ public class TagRegistry<T> {
return true;
}
/**
* Same as registerTag(String tag) but allows a description to be added.
*
* @param tag Tag to be used on command line
* @param desc
* @return if the tag was registered
*/
public boolean registerTag(String tag, String desc) {
private boolean registerTag(String tag, String desc) {
if (registerTag(tag)) {
this.tagDesc.put(tag, desc);
return true;
@ -130,7 +112,7 @@ public class TagRegistry<T> {
* File must extend
* @return if the tag has been registered or if it already exists.
*/
public boolean registerTag(String tag, Object tagHandler) {
public boolean registerTag(String tag, Tag tagHandler) {
if (tag == null) {
this.portalsCore.getInfoLogger().logWarning("A tag cannot be null.");
@ -141,14 +123,14 @@ public class TagRegistry<T> {
return false;
}
if (tagHandler instanceof TagHandler.Activation) {
this.activationHandlers.put(tag, (TagHandler.Activation<T>) tagHandler);
if (tagHandler instanceof Tag.Activation tagActivation) {
this.activationHandlers.put(tag, tagActivation);
}
if (tagHandler instanceof TagHandler.TagStatus) {
this.statusHandlers.put(tag, (TagHandler.TagStatus<T>) tagHandler);
if (tagHandler instanceof Tag.TagStatus tagStatus) {
this.statusHandlers.put(tag, tagStatus);
}
if (tagHandler instanceof TagHandler.Creation) {
this.creationHandlers.put(tag, (TagHandler.Creation<T>) tagHandler);
if (tagHandler instanceof Tag.Creation tagCreation) {
this.creationHandlers.put(tag, tagCreation);
}
return true;
}

View File

@ -0,0 +1,34 @@
package com.sekwah.advancedportals.core.registry;
/**
* Something that a tag can be executed on.
*/
public interface TagTarget {
/**
* Get the values for the arg
* @param argName
* @return
*/
String[] getArgValues(String argName);
/**
* Set the values for the arg
* @param argName
* @param argValues
*/
void setArgValues(String argName, String[] argValues);
/**
* Add a new arg to the tag
* @param argName
* @param argValues
*/
void addArg(String argName, String argValues);
/**
* Remove the arg entirely from the target
* @param arg
*/
void removeArg(String arg);
}

View File

@ -3,11 +3,16 @@ package com.sekwah.advancedportals.core.serializeddata;
public class DataTag {
public final String NAME;
public final String VALUE;
public final String[] VALUES;
public DataTag(String argName, String value) {
public DataTag(String argName, String values) {
this.NAME = argName;
this.VALUE = value;
this.VALUES = new String[]{values};
}
public DataTag(String argName, String[] values) {
this.NAME = argName;
this.VALUES = values;
}
}

View File

@ -71,7 +71,7 @@ public class DestinationServices {
Destination desti = new Destination(playerLocation);
for(DataTag portalTag : tags) {
desti.setArg(portalTag);
desti.setArgValues(portalTag);
}
for(DataTag destiTag : tags) {
// TODO sort tag handle registry

View File

@ -0,0 +1,31 @@
package com.sekwah.advancedportals.core.tags.activation;
import com.sekwah.advancedportals.core.connector.containers.PlayerContainer;
import com.sekwah.advancedportals.core.registry.TagTarget;
import com.sekwah.advancedportals.core.warphandler.ActivationData;
import com.sekwah.advancedportals.core.warphandler.Tag;
public class DestiTag implements Tag.Activation {
private final TagType[] tagTypes = new TagType[]{ TagType.PORTAL };
@Override
public TagType[] getTagTypes() {
return tagTypes;
}
@Override
public boolean preActivated(TagTarget target, PlayerContainer player, ActivationData activeData, String[] argData) {
return false;
}
@Override
public void postActivated(TagTarget target, PlayerContainer player, ActivationData activeData, String[] argData) {
}
@Override
public boolean activated(TagTarget target, PlayerContainer player, ActivationData activeData, String[] argData) {
return false;
}
}

View File

@ -3,11 +3,12 @@ package com.sekwah.advancedportals.core.util;
import com.sekwah.advancedportals.core.serializeddata.DataTag;
import java.util.ArrayList;
import java.util.HashMap;
public class TagReader {
public static ArrayList<DataTag> getTagsFromArgs(String[] args) {
ArrayList<DataTag> tags = new ArrayList<>();
HashMap<String, ArrayList<String>> tagMap = new HashMap<>();
StringBuilder currentValue = new StringBuilder();
String currentIdentifier = null;
boolean inQuotes = false;
@ -15,7 +16,15 @@ public class TagReader {
for (String arg : args) {
if (arg.contains(":") && !inQuotes) {
if (currentIdentifier != null) {
tags.add(new DataTag(currentIdentifier, currentValue.toString()));
ArrayList<String> tags;
if(tagMap.containsKey(currentIdentifier)) {
tags = tagMap.get(currentIdentifier);
}
else {
tags = new ArrayList<>();
tagMap.put(currentIdentifier, tags);
}
tags.add(currentValue.toString());
}
int colonIndex = arg.indexOf(':');
currentIdentifier = arg.substring(0, colonIndex);
@ -34,7 +43,21 @@ public class TagReader {
}
if (currentIdentifier != null) {
tags.add(new DataTag(currentIdentifier, currentValue.toString().replace("\"", "")));
ArrayList<String> tags;
if(tagMap.containsKey(currentIdentifier)) {
tags = tagMap.get(currentIdentifier);
}
else {
tags = new ArrayList<>();
tagMap.put(currentIdentifier, tags);
}
tags.add(currentValue.toString().replace("\"", ""));
}
// Loop over values in the map and create the tags
ArrayList<DataTag> tags = new ArrayList<>();
for (String key : tagMap.keySet()) {
tags.add(new DataTag(key, tagMap.get(key).toArray(new String[0])));
}
return tags;

View File

@ -1,25 +1,37 @@
package com.sekwah.advancedportals.core.warphandler;
import com.sekwah.advancedportals.core.connector.containers.PlayerContainer;
import com.sekwah.advancedportals.core.registry.TagTarget;
/**
* If a tag can be used for any of them then either make it cast the target or if it doesnt need a target
* If a tag can be used for any of them then either make it cast the target or if it doesn't need a target
* then the exact same tag can be registered into both and ignore the portal info.
*
* Will probably make better documentation on how to do so or some tutorial videos though take a look at the source code
* on github for how the current tags are added.
* on GitHub for how the current tags are added.
*
* Also not sure if its good practice or not in java however these all extend TagHandler so they can be accepted in 1
* Also, not sure if its good practice or not in java however these all extend TagHandler, so they can be accepted in 1
* method nicer than if they didn't
*
* @author sekwah41
*/
public interface TagHandler {
public interface Tag {
enum TagType {
PORTAL,
DESTINATION
}
/**
* Used to flag where the auto complete should show more or less info.
* @return
*/
TagType[] getTagTypes();
/**
* The events for portal creation and destroying
*/
interface Creation<T> extends TagHandler {
interface Creation extends Tag {
/**
* Example if the player does not have access to use the tag.
@ -27,7 +39,7 @@ public interface TagHandler {
* @param player if null then created by the server or a plugin
* @param argData
*/
void created(T target, PlayerContainer player, String argData);
void created(TagTarget target, PlayerContainer player, String[] argData);
/**
* Example if the player does not have access to remove the portal or destination.
@ -35,7 +47,7 @@ public interface TagHandler {
* @param player if null then removed by the server or a plugin
* @param argData
*/
void destroyed(T target, PlayerContainer player, String argData);
void destroyed(TagTarget target, PlayerContainer player, String[] argData);
}
@ -53,10 +65,8 @@ public interface TagHandler {
* - Desti.activate
* Portal.postActivate - when desti tag is hit (if listed) then the next action is activated
* - Desti.postActivate
*
* @param <T>
*/
interface Activation<T> extends TagHandler {
interface Activation extends Tag {
/**
* Activates before the main part of activation. This should be for prechecks e.g. if the player has enough
@ -68,7 +78,7 @@ public interface TagHandler {
*
* @return If the tag has allowed the warp
*/
boolean preActivated(T target, PlayerContainer player, ActivationData activeData, String argData);
boolean preActivated(TagTarget target, PlayerContainer player, ActivationData activeData, String[] argData);
/**
* Activates after activation, should be used for actions such as removing money for a teleport.
@ -79,7 +89,7 @@ public interface TagHandler {
* @param activeData
* @param argData
*/
void postActivated(T target, PlayerContainer player, ActivationData activeData, String argData);
void postActivated(TagTarget target, PlayerContainer player, ActivationData activeData, String[] argData);
/**
* Activates if the portal is allowed from preActivating. Should be used to set the intended warp location
@ -95,29 +105,36 @@ public interface TagHandler {
*
* @return If the tag has allowed the warp
*/
boolean activated(T target, PlayerContainer player, ActivationData activeData, String argData);
boolean activated(TagTarget target, PlayerContainer player, ActivationData activeData, String[] argData);
}
interface TagStatus<T> extends TagHandler {
/**
* Triggers when a tag is added or removed from a portal or destination
*/
interface TagStatus extends Tag {
/**
* If the user has access to add the tag (this does not include being added on creation)
*
* @param player
* @param argData
* @param target the target of the tag
* @param player if null then removed by the server or a plugin
* @param argData the data for the tag
* @param index the index of the tag in the list (if it is the only tag it will be 0)
* @return if the tag will be added.
*/
boolean tagAdded(T target, PlayerContainer player, String argData);
boolean tagAdded(TagTarget target, PlayerContainer player, int index, String argData);
/**
* If the user has access to remove the tag (this does not include being added on destruction)
*
* @param player
* @param argData
* @param target the target of the tag
* @param player if null then removed by the server or a plugin
* @param argData the data of the tag to be removed
* @param index the index of the tag in the list (if it is the only tag it will be 0)
* @return if the tag will be removed.
*/
boolean tagRemoved(T target, PlayerContainer player, String argData);
boolean tagRemoved(TagTarget target, PlayerContainer player, int index, String argData);
}