322 lines
12 KiB
Java
322 lines
12 KiB
Java
package com.hypixel.hytale.server.npc.role.builders;
|
|
|
|
import com.google.gson.JsonElement;
|
|
import com.hypixel.hytale.codec.schema.config.Schema;
|
|
import com.hypixel.hytale.codec.schema.config.StringSchema;
|
|
import com.hypixel.hytale.function.function.TriFunction;
|
|
import com.hypixel.hytale.function.function.TriToIntFunction;
|
|
import com.hypixel.hytale.logger.sentry.SkipSentryException;
|
|
import com.hypixel.hytale.server.npc.NPCPlugin;
|
|
import com.hypixel.hytale.server.npc.asset.builder.Builder;
|
|
import com.hypixel.hytale.server.npc.asset.builder.BuilderDescriptorState;
|
|
import com.hypixel.hytale.server.npc.asset.builder.BuilderInfo;
|
|
import com.hypixel.hytale.server.npc.asset.builder.BuilderModifier;
|
|
import com.hypixel.hytale.server.npc.asset.builder.BuilderParameters;
|
|
import com.hypixel.hytale.server.npc.asset.builder.BuilderSupport;
|
|
import com.hypixel.hytale.server.npc.asset.builder.SpawnableWithModelBuilder;
|
|
import com.hypixel.hytale.server.npc.asset.builder.StateMappingHelper;
|
|
import com.hypixel.hytale.server.npc.asset.builder.holder.StringHolder;
|
|
import com.hypixel.hytale.server.npc.role.Role;
|
|
import com.hypixel.hytale.server.npc.util.expression.ExecutionContext;
|
|
import com.hypixel.hytale.server.npc.util.expression.Scope;
|
|
import com.hypixel.hytale.server.npc.validators.NPCLoadTimeValidationHelper;
|
|
import com.hypixel.hytale.server.spawning.ISpawnableWithModel;
|
|
import com.hypixel.hytale.server.spawning.SpawnTestResult;
|
|
import com.hypixel.hytale.server.spawning.SpawningContext;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.Objects;
|
|
import java.util.function.BiFunction;
|
|
import java.util.function.Supplier;
|
|
import java.util.logging.Level;
|
|
import javax.annotation.Nonnull;
|
|
import javax.annotation.Nullable;
|
|
|
|
public class BuilderRoleVariant extends SpawnableWithModelBuilder<Role> {
|
|
protected final StringHolder reference = new StringHolder();
|
|
protected int referenceIndex;
|
|
protected BuilderModifier modifier;
|
|
|
|
@Nullable
|
|
public Role build(@Nonnull BuilderSupport builderSupport) {
|
|
return this.executeOnSuperRole(builderSupport, Builder::build, () -> null);
|
|
}
|
|
|
|
@Override
|
|
public StateMappingHelper getStateMappingHelper() {
|
|
Builder<Object> parentBuilder = this.builderManager.getCachedBuilder(this.referenceIndex, Role.class);
|
|
return parentBuilder.getStateMappingHelper();
|
|
}
|
|
|
|
@Override
|
|
public boolean validate(
|
|
String configName, @Nonnull NPCLoadTimeValidationHelper validationHelper, @Nonnull ExecutionContext context, Scope globalScope, List<String> errors
|
|
) {
|
|
Builder<Object> roleBuilder = this.builderManager.getCachedBuilder(this.referenceIndex, Role.class);
|
|
if (!(roleBuilder instanceof ISpawnableWithModel)) {
|
|
NPCPlugin.get().getLogger().at(Level.SEVERE).log("Variant %s is of a non-spawnable template!", configName);
|
|
return false;
|
|
} else {
|
|
validationHelper.setIsVariant();
|
|
String combatConfig = this.modifier.getCombatConfig();
|
|
if (combatConfig != null && context.getCombatConfig() == null) {
|
|
context.setCombatConfig(combatConfig);
|
|
}
|
|
|
|
Map<String, String> interactionVars = this.modifier.getInteractionVars();
|
|
if (interactionVars != null && context.getInteractionVars() == null) {
|
|
context.setInteractionVars(interactionVars);
|
|
}
|
|
|
|
BuilderParameters builderParameters = roleBuilder.getBuilderParameters();
|
|
Scope newScope = this.modifier.createScope(context, builderParameters, null);
|
|
Scope oldScope = context.setScope(newScope);
|
|
boolean result = roleBuilder.validate(configName, validationHelper, context, context.getScope(), errors);
|
|
context.setScope(oldScope);
|
|
return result;
|
|
}
|
|
}
|
|
|
|
@Nonnull
|
|
@Override
|
|
public Builder<Role> readConfig(@Nonnull JsonElement data) {
|
|
if (this.isCreatingSchema()) {
|
|
Map<String, Schema> props = this.builderSchema.getProperties();
|
|
StringSchema schema = new StringSchema();
|
|
schema.setHytaleAssetRef("NPCRole");
|
|
props.put("Reference", schema);
|
|
props.put("Modify", BuilderModifier.toSchema(this.builderSchemaContext));
|
|
return this;
|
|
} else {
|
|
if (!this.isCreatingDescriptor()) {
|
|
BuilderModifier.readModifierObject(
|
|
this.expectJsonObject(data, this.getLabel()),
|
|
this.getBuilderParameters(),
|
|
this.reference,
|
|
holder -> {},
|
|
modifier -> this.modifier = modifier,
|
|
this.stateHelper,
|
|
this.extraInfo
|
|
);
|
|
if (!this.reference.isStatic()) {
|
|
throw new IllegalStateException("Computable component references are not supported for Role Variants");
|
|
}
|
|
|
|
this.referenceIndex = this.getBuilderManager().getOrCreateIndex(this.reference.get(null));
|
|
this.builderParameters.addDependency(this.referenceIndex);
|
|
}
|
|
|
|
this.ignoreAttribute("Reference");
|
|
this.ignoreAttribute("Modify");
|
|
this.ignoreAttribute("$Label");
|
|
return this;
|
|
}
|
|
}
|
|
|
|
@Nonnull
|
|
@Override
|
|
public Class<Role> category() {
|
|
return Role.class;
|
|
}
|
|
|
|
@Nonnull
|
|
@Override
|
|
public String getIdentifier() {
|
|
BuilderInfo builderInfo = NPCPlugin.get().getBuilderInfo(this);
|
|
Objects.requireNonNull(builderInfo, "Have builder but can't get builderInfo for it");
|
|
return builderInfo.getKeyName();
|
|
}
|
|
|
|
@Nonnull
|
|
@Override
|
|
public SpawnTestResult canSpawn(@Nonnull SpawningContext spawningContext) {
|
|
return this.executeOnSuperRole(
|
|
spawningContext, (roleBuilder, _context) -> ((ISpawnableWithModel)roleBuilder).canSpawn(_context), () -> SpawnTestResult.FAIL_NOT_SPAWNABLE
|
|
);
|
|
}
|
|
|
|
@Nullable
|
|
@Override
|
|
public String getSpawnModelName(@Nonnull ExecutionContext context, Scope modifierScope) {
|
|
return this.executeOnSuperRole(
|
|
context,
|
|
modifierScope,
|
|
(roleBuilder, _context, _modifierScope) -> ((ISpawnableWithModel)roleBuilder).getSpawnModelName(_context, _modifierScope),
|
|
() -> null
|
|
);
|
|
}
|
|
|
|
@Override
|
|
public Scope createModifierScope(@Nonnull ExecutionContext executionContext) {
|
|
Scope originalScope = executionContext.getScope();
|
|
Builder<Role> roleBuilder = this;
|
|
Scope scope = null;
|
|
|
|
do {
|
|
BuilderRoleVariant variantBuilder = (BuilderRoleVariant)roleBuilder;
|
|
roleBuilder = this.builderManager.getCachedBuilder(variantBuilder.referenceIndex, Role.class);
|
|
if (!(roleBuilder instanceof ISpawnableWithModel)) {
|
|
throw new IllegalStateException("Cannot instantiate a variant of something that isn't a spawnable role!");
|
|
}
|
|
|
|
scope = variantBuilder.modifier.createScope(executionContext, roleBuilder.getBuilderParameters(), scope);
|
|
executionContext.setScope(scope);
|
|
} while (roleBuilder instanceof BuilderRoleVariant);
|
|
|
|
executionContext.setScope(originalScope);
|
|
return scope;
|
|
}
|
|
|
|
@Nonnull
|
|
@Override
|
|
public Scope createExecutionScope() {
|
|
return this.getBuilderParameters().createScope();
|
|
}
|
|
|
|
@Override
|
|
public void markNeedsReload() {
|
|
NPCPlugin.get().setRoleBuilderNeedsReload(this);
|
|
}
|
|
|
|
@Nonnull
|
|
@Override
|
|
public String getShortDescription() {
|
|
return "Create a variant from an existing NPC JSON file";
|
|
}
|
|
|
|
@Nonnull
|
|
@Override
|
|
public String getLongDescription() {
|
|
return "Create a variant from an existing NPC JSON file";
|
|
}
|
|
|
|
@Nonnull
|
|
@Override
|
|
public BuilderDescriptorState getBuilderDescriptorState() {
|
|
return BuilderDescriptorState.WorkInProgress;
|
|
}
|
|
|
|
@Override
|
|
public final boolean isEnabled(ExecutionContext context) {
|
|
return true;
|
|
}
|
|
|
|
public int getReferenceIndex() {
|
|
return this.referenceIndex;
|
|
}
|
|
|
|
@Override
|
|
public boolean isMemory(@Nonnull ExecutionContext context, Scope modifierScope) {
|
|
Boolean result = this.executeOnSuperRole(
|
|
context, modifierScope, (roleBuilder, _context, _modifierScope) -> ((ISpawnableWithModel)roleBuilder).isMemory(_context, _modifierScope), () -> null
|
|
);
|
|
return result != null ? result : false;
|
|
}
|
|
|
|
@Nullable
|
|
@Override
|
|
public String getMemoriesCategory(@Nonnull ExecutionContext context, Scope modifierScope) {
|
|
return this.executeOnSuperRole(
|
|
context,
|
|
modifierScope,
|
|
(roleBuilder, _context, _modifierScope) -> ((ISpawnableWithModel)roleBuilder).getMemoriesCategory(_context, _modifierScope),
|
|
() -> null
|
|
);
|
|
}
|
|
|
|
@Nullable
|
|
@Override
|
|
public String getMemoriesNameOverride(@Nonnull ExecutionContext context, Scope modifierScope) {
|
|
return this.executeOnSuperRole(
|
|
context,
|
|
modifierScope,
|
|
(roleBuilder, _context, _modifierScope) -> ((ISpawnableWithModel)roleBuilder).getMemoriesNameOverride(_context, _modifierScope),
|
|
() -> null
|
|
);
|
|
}
|
|
|
|
@Nonnull
|
|
@Override
|
|
public String getNameTranslationKey(ExecutionContext context, Scope modifierScope) {
|
|
return this.executeOnSuperRole(
|
|
context,
|
|
modifierScope,
|
|
(roleBuilder, _context, _modifierScope) -> ((ISpawnableWithModel)roleBuilder).getNameTranslationKey(_context, _modifierScope),
|
|
() -> {
|
|
throw new SkipSentryException(new IllegalStateException("Failed to get translation key for role!"));
|
|
}
|
|
);
|
|
}
|
|
|
|
protected <V> V executeOnSuperRole(
|
|
@Nonnull BuilderSupport builderSupport, @Nonnull BiFunction<Builder<Role>, BuilderSupport, V> func, @Nonnull Supplier<V> failed
|
|
) {
|
|
Builder<Role> roleBuilder = builderSupport.getBuilderManager().getCachedBuilder(this.referenceIndex, Role.class);
|
|
if (!(roleBuilder instanceof ISpawnableWithModel)) {
|
|
return failed.get();
|
|
} else {
|
|
BuilderParameters builderParameters = roleBuilder.getBuilderParameters();
|
|
Scope newScope = this.modifier.createScope(builderSupport, builderParameters, null);
|
|
ExecutionContext context = builderSupport.getExecutionContext();
|
|
String combatConfig = this.modifier.getCombatConfig();
|
|
if (combatConfig != null && context.getCombatConfig() == null) {
|
|
context.setCombatConfig(combatConfig);
|
|
}
|
|
|
|
Map<String, String> interactionVars = this.modifier.getInteractionVars();
|
|
if (interactionVars != null && context.getInteractionVars() == null) {
|
|
context.setInteractionVars(interactionVars);
|
|
}
|
|
|
|
Scope oldScope = context.setScope(newScope);
|
|
builderSupport.setGlobalScope(newScope);
|
|
V v = func.apply(roleBuilder, builderSupport);
|
|
context.setScope(oldScope);
|
|
return v;
|
|
}
|
|
}
|
|
|
|
protected <V> V executeOnSuperRole(
|
|
@Nonnull SpawningContext spawningContext, @Nonnull BiFunction<Builder<Role>, SpawningContext, V> func, @Nonnull Supplier<V> failed
|
|
) {
|
|
Builder<Role> roleBuilder = this.builderManager.getCachedBuilder(this.referenceIndex, Role.class);
|
|
if (!(roleBuilder instanceof ISpawnableWithModel)) {
|
|
return failed.get();
|
|
} else {
|
|
ExecutionContext executionContext = spawningContext.getExecutionContext();
|
|
Scope oldScope = executionContext.setScope(spawningContext.getModifierScope());
|
|
V v = func.apply(roleBuilder, spawningContext);
|
|
executionContext.setScope(oldScope);
|
|
return v;
|
|
}
|
|
}
|
|
|
|
protected <V> V executeOnSuperRole(
|
|
@Nonnull ExecutionContext context, Scope modifierScope, @Nonnull TriFunction<Builder<Role>, ExecutionContext, Scope, V> func, @Nonnull Supplier<V> failed
|
|
) {
|
|
Builder<Role> roleBuilder = this.builderManager.getCachedBuilder(this.referenceIndex, Role.class);
|
|
if (!(roleBuilder instanceof ISpawnableWithModel)) {
|
|
return failed.get();
|
|
} else {
|
|
Scope oldScope = context.setScope(modifierScope);
|
|
V v = func.apply(roleBuilder, context, modifierScope);
|
|
context.setScope(oldScope);
|
|
return v;
|
|
}
|
|
}
|
|
|
|
protected int executeOnSuperRole(
|
|
@Nonnull ExecutionContext context, Scope modifierScope, @Nonnull TriToIntFunction<Builder<Role>, ExecutionContext, Scope> func, int failed
|
|
) {
|
|
Builder<Role> roleBuilder = this.builderManager.getCachedBuilder(this.referenceIndex, Role.class);
|
|
if (!(roleBuilder instanceof ISpawnableWithModel)) {
|
|
return failed;
|
|
} else {
|
|
Scope oldScope = context.setScope(modifierScope);
|
|
int v = func.apply(roleBuilder, context, modifierScope);
|
|
context.setScope(oldScope);
|
|
return v;
|
|
}
|
|
}
|
|
}
|