Skip to content

Commit

Permalink
fallback tags
Browse files Browse the repository at this point in the history
  • Loading branch information
mcmonkey4eva committed Mar 27, 2021
1 parent 089efcd commit 90dc874
Show file tree
Hide file tree
Showing 8 changed files with 123 additions and 132 deletions.
Expand Up @@ -540,6 +540,10 @@ public String toString() {
// For example, "on player breaks regex:(?i)\d+_customitem:"
// Note that generally regex should be avoided whenever you can, as it's inherently hard to track exactly what it's doing at-a-glance, and may have unexpected edge case errors.
//
// If you want to match anything *except* a specific value, just prefix the matcher with '!'
// For example, on player breaks !stone:" will fire for a player breaking any block type OTHER THAN stone.
// This can be combined with other match modes, like "on player breaks !*wood|*planks|*log:" will fire for any block break other than any wood variant.
//
// See also <@link language script event object matchables>.
// -->

Expand Down
56 changes: 49 additions & 7 deletions src/main/java/com/denizenscript/denizencore/tags/Attribute.java
@@ -1,15 +1,13 @@
package com.denizenscript.denizencore.tags;

import com.denizenscript.denizencore.objects.ObjectTag;
import com.denizenscript.denizencore.objects.core.ElementTag;
import com.denizenscript.denizencore.scripts.ScriptEntry;
import com.denizenscript.denizencore.utilities.CoreUtilities;
import com.denizenscript.denizencore.utilities.DefinitionProvider;
import com.denizenscript.denizencore.utilities.debugging.Debug;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.*;

public class Attribute {

Expand Down Expand Up @@ -91,6 +89,7 @@ else if (chr == '.' && !(x > 0 && isNumber(attrInp[x + 1]) && isNumber(attrInp[x

public AttributeComponent[] attributes;
public ObjectTag[] contexts;
public Boolean[] filled;

ScriptEntry scriptEntry;
public TagContext context;
Expand Down Expand Up @@ -124,6 +123,9 @@ public Attribute(Attribute ref, ScriptEntry scriptEntry, TagContext context) {
attributes = ref.attributes;
contexts = new ObjectTag[attributes.length];
setHadAlternative(ref.hadAlternative);
if (context == null || context.debug) {
filled = new Boolean[attributes.length];
}
}

public Attribute(String attributes, ScriptEntry scriptEntry, TagContext context) {
Expand All @@ -132,6 +134,9 @@ public Attribute(String attributes, ScriptEntry scriptEntry, TagContext context)
this.context = context;
this.attributes = separate_attributes(attributes);
contexts = new ObjectTag[this.attributes.length];
if (context == null || context.debug) {
filled = new Boolean[this.attributes.length];
}
}

public boolean matches(String string) {
Expand Down Expand Up @@ -186,6 +191,11 @@ public boolean isComplete() {

public Attribute fulfill(int attributes) {
resetErrorTrack();
if (filled != null) {
for (int i = 0; i < attributes; i++) {
filled[fulfilled + i] = Boolean.TRUE;
}
}
fulfilled += attributes;
return this;
}
Expand Down Expand Up @@ -353,8 +363,34 @@ public String getContext(int attribute) {
// You want to solve errors in testing, not ten months later when a player mentions to you "that shop NPC let me buy things even when I had $0"!
//
// -->
public static final HashMap<String, TagRunnable.BaseInterface> fallbackTags = new HashMap<>();

static {
fallbackTags.put("if_null", (attribute) -> {
if (!attribute.hasContext(1)) {
return null;
}
return attribute.getContextObject(1);
});
fallbackTags.put("exists", (attribute) -> {
return new ElementTag(false);
});
}

public boolean hasAlternative() {
return hadAlternative;
if (hadAlternative) {
return true;
}
return getFallbackTagIndex() != -1;
}

public int getFallbackTagIndex() {
for (int i = fulfilled + 1; i < attributes.length; i++) {
if (fallbackTags.containsKey(attributes[i].key)) {
return i;
}
}
return -1;
}

public void setHadAlternative(boolean hadAlternative) {
Expand Down Expand Up @@ -455,12 +491,18 @@ public String unfilledString() {
public String toString() {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < attributes.length; i++) {
sb.append(i < fulfilled ? "<GR>" : (i == fulfilled ? "<R>" : "<Y>")).append(attributes[i].key);
if (filled != null) {
sb.append(filled[i] == null ? "<Y>" : (filled[i] ? "<GR>" : "<R>"));
}
else {
sb.append(i < fulfilled ? "<GR>" : (i == fulfilled ? "<R>" : "<Y>"));
}
sb.append(attributes[i].key);
if (contexts[i] != null) {
sb.append("<LG>[<A>").append(contexts[i]).append("<LG>].");
}
else if (attributes[i].context != null) {
sb.append("<LG>[<R>").append(attributes[i].context).append("<LG>].");
sb.append("<LG>[<Y>").append(attributes[i].context).append("<LG>].");
}
else {
sb.append("<LG>.");
Expand Down
Expand Up @@ -83,6 +83,33 @@ public ObjectTagProcessor() {
}
return null;
});

// <--[tag]
// @attribute <ObjectTag.if_null[<object>]>
// @returns ObjectTag
// @description
// If the object is null (or the tag errors), this will return the input object.
// If the object isn't null, the input won't be parsed, and the original object will be returned.
// For example, "<player.if_null[<npc>]>" will return the player if there is a player, and otherwise will return the NPC.
// This functions as a fallback - meaning, if the tag up to this point errors, that error will be hidden.
// -->
registerTag("if_null", (attribute, object) -> {
if (!attribute.hasContext(1)) {
return null;
}
return object;
});

// <--[tag]
// @attribute <ObjectTag.exists>
// @returns ElementTag(Boolean)
// @description
// Returns true if the object exists (is non-null). Returns false if the object doesn't exist, is null, or the tag errored.
// This functions as a fallback - meaning, if the tag up to this point errors, that error will be hidden.
// -->
registerTag("exists", (attribute, object) -> {
return new ElementTag(true);
});
}

public void registerFutureTagDeprecation(String name, String... deprecatedVariants) {
Expand Down
Expand Up @@ -14,7 +14,6 @@ public class ReplaceableTagEvent {

private boolean wasReplaced = false;

private ObjectTag alternative_tagged = null;
private String replaced;
private String value_tagged = null;
private Attribute core_attributes = null;
Expand Down Expand Up @@ -192,118 +191,46 @@ public boolean matches(String... tagNames) {
return false;
}

////////
// Replaceable Tag 'Parts'
// <name.type.subtype.specifier:value>

// Name

public String getName() {
return core_attributes.getAttributeWithoutContext(1);
}

public String getNameContext() {
return core_attributes.getContext(1);
}

public boolean hasNameContext() {
return core_attributes.hasContext(1);
}

// Type

@Deprecated
public String getType() {
return core_attributes.getAttributeWithoutContext(2);
}

@Deprecated
public boolean hasType() {
return core_attributes.getAttribute(2).length() > 0;
}

@Deprecated
public String getTypeContext() {
return core_attributes.getContext(2);
}

@Deprecated
public boolean hasTypeContext() {
return core_attributes.hasContext(2);
}

// Subtype

@Deprecated
public String getSubType() {
return core_attributes.getAttributeWithoutContext(3);
}

@Deprecated
public boolean hasSubType() {
return core_attributes.getAttribute(3).length() > 0;
}

@Deprecated
public String getSubTypeContext() {
return core_attributes.getContext(3);
}

@Deprecated
public boolean hasSubTypeContext() {
return core_attributes.hasContext(3);
}

// Specifier

@Deprecated
public String getSpecifier() {
return core_attributes.getAttributeWithoutContext(4);
}

@Deprecated
public boolean hasSpecifier() {
return core_attributes.getAttribute(4).length() > 0;
}

@Deprecated
public String getSpecifierContext() {
return core_attributes.getContext(4);
}

@Deprecated
public boolean hasSpecifierContext() {
return core_attributes.hasContext(4);
}

// Value

public String getValue() {
if (value_tagged == null) {
value_tagged = TagManager.tag(mainRef.value, context);
}
return value_tagged;
}

@Deprecated
public boolean hasValue() {
return mainRef.value != null;
}

// Alternative
public TagRunnable.BaseInterface alternateBase;

public ObjectTag getAlternative() {
if (!hasAlternative()) {
return null;
int index = core_attributes.getFallbackTagIndex();
if (index != -1) {
if (core_attributes.filled != null) {
core_attributes.filled[core_attributes.fulfilled] = Boolean.FALSE;
}
core_attributes.fulfilled = index;
alternateBase = Attribute.fallbackTags.get(core_attributes.getAttributeWithoutContext(1));
return TagManager.readSingleTagObjectNoDebug(context, this);
}
if (alternative_tagged != null) {
return alternative_tagged;
if (mainRef.alternative != null) {
return TagManager.tagObject(mainRef.alternative, context);
}
alternative_tagged = TagManager.tagObject(mainRef.alternative, context);
return alternative_tagged;
return null;
}

public boolean hasAlternative() {
return mainRef.alternative != null;
if (mainRef.alternative != null) {
return true;
}
return core_attributes.hasAlternative();
}

// Other internal mechanics
Expand Down
10 changes: 7 additions & 3 deletions src/main/java/com/denizenscript/denizencore/tags/TagManager.java
Expand Up @@ -69,7 +69,7 @@ public static void fireEvent(ReplaceableTagEvent event) {
if (Debug.verbose) {
Debug.log("Tag fire: " + event.raw_tag + ", " + event.getAttributes().attributes[0].rawKey.contains("@") + ", " + event.hasAlternative() + "...");
}
TagRunnable.BaseInterface baseHandler = event.mainRef.tagBaseHandler;
TagRunnable.BaseInterface baseHandler = event.alternateBase != null ? event.alternateBase : event.mainRef.tagBaseHandler;
if (baseHandler != null) {
Attribute attribute = event.getAttributes();
try {
Expand Down Expand Up @@ -167,8 +167,7 @@ public static ObjectTag readSingleTagObject(ParseableTagPiece tag, TagContext co

public static boolean recentTagError = true;

public static ObjectTag readSingleTagObject(TagContext context, ReplaceableTagEvent event) {
// Call Event
public static ObjectTag readSingleTagObjectNoDebug(TagContext context, ReplaceableTagEvent event) {
int tT = DenizenCore.getImplementation().getTagTimeout();
if (Debug.verbose) {
Debug.log("Tag read: " + event.raw_tag + ", " + tT + "...");
Expand All @@ -182,6 +181,11 @@ public static ObjectTag readSingleTagObject(TagContext context, ReplaceableTagEv
if (!event.replaced() && event.hasAlternative()) {
event.setReplacedObject(event.getAlternative());
}
return event.getReplacedObj();
}

public static ObjectTag readSingleTagObject(TagContext context, ReplaceableTagEvent event) {
readSingleTagObjectNoDebug(context, event);
if (context.debug && event.replaced()) {
DenizenCore.getImplementation().debugTagFill(context, event.toString(), event.getReplacedObj().debuggable());
}
Expand Down
Expand Up @@ -50,16 +50,18 @@ public void contextTags(ReplaceableTagEvent event) {

public void savedEntryTags(ReplaceableTagEvent event) {
if (!event.matches("entry", "e")
|| event.getScriptEntry() == null
|| !event.hasNameContext()) {
|| event.getScriptEntry() == null) {
return;
}
Attribute attribute = event.getAttributes();
if (attribute.hasContext(1)) {
return;
}
if (event.matches("e")) {
Deprecations.entryShorthand.warn(event.getScriptEntry());
}
if (event.getScriptEntry().getResidingQueue() != null) {
String id = event.getNameContext();
Attribute attribute = event.getAttributes();
String id = attribute.getContext(1);
ScriptEntry held = event.getScriptEntry().getResidingQueue().getHeldScriptEntry(id);
if (held == null) {
if (!event.hasAlternative()) {
Expand Down
Expand Up @@ -42,18 +42,18 @@ public void queueTag(ReplaceableTagEvent event) {

// Handle <queue[id]. ...> tags

if (event.hasNameContext()) {
if (!ScriptQueue.queueExists(event.getNameContext())) {
Attribute attribute = event.getAttributes();

if (attribute.hasContext(1)) {
QueueTag queue = attribute.contextAsType(1, QueueTag.class);
if (queue == null) {
return;
}
else {
event.setReplacedObject(CoreUtilities.autoAttrib(new QueueTag(ScriptQueue.getExistingQueue(event.getNameContext())),
event.getAttributes().fulfill(1)));
}
event.setReplacedObject(CoreUtilities.autoAttrib(queue, event.getAttributes().fulfill(1)));
return;
}

Attribute attribute = event.getAttributes().fulfill(1);
attribute = attribute.fulfill(1);

// Otherwise, try to use queue in a static manner.

Expand Down

0 comments on commit 90dc874

Please sign in to comment.