de.rpgframework.genericrpg.items.GearTool Maven / Gradle / Ivy
The newest version!
package de.rpgframework.genericrpg.items;
import java.lang.System.Logger;
import java.lang.System.Logger.Level;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;
import de.rpgframework.core.RoleplayingSystem;
import de.rpgframework.genericrpg.ToDoElement;
import de.rpgframework.genericrpg.ToDoElement.Severity;
import de.rpgframework.genericrpg.chargen.OperationResult;
import de.rpgframework.genericrpg.data.ApplyTo;
import de.rpgframework.genericrpg.data.Choice;
import de.rpgframework.genericrpg.data.DataErrorException;
import de.rpgframework.genericrpg.data.Decision;
import de.rpgframework.genericrpg.data.IReferenceResolver;
import de.rpgframework.genericrpg.data.Lifeform;
import de.rpgframework.genericrpg.data.ReferenceError;
import de.rpgframework.genericrpg.data.ReferenceException;
import de.rpgframework.genericrpg.items.formula.ResolveFormulasInRequirementsStep;
import de.rpgframework.genericrpg.items.formula.ResolveFormulasStep;
import de.rpgframework.genericrpg.modification.Modification;
import de.rpgframework.genericrpg.modification.ModifiedObjectType;
/**
* @author prelle
*
*/
public class GearTool {
public final static String SELECTION_NOT_ALLOWED = "Selection not allowed";
private final static Logger logger = CarriedItem.logger;
static CarriedItemProcessor[] PHASE1_STEPS = new CarriedItemProcessor[] {
new ResolveVariantStep(),
new CopyResolvedAttributesStep(),
new ApplyDecisionsStep(),
new ResolveFormulasStep(),
new CopyRequirementsStep(),
new ResolveFormulasInRequirementsStep(),
new CopyUsagesStep()
//new RecurseEmbeddedItems(),
};
static CarriedItemProcessor[] PHASE2_STEPS = new CarriedItemProcessor[] {
new RecurseEmbeddedItems(),
};
private static Map PER_RPG_PHASE1_STEPS = new HashMap();
private static Map PER_RPG_PHASE2_STEPS = new HashMap();
//-------------------------------------------------------------------
public static void setPerRPGStatsPhase1(RoleplayingSystem rules, CarriedItemProcessor[] steps) {
PER_RPG_PHASE1_STEPS.put(rules, steps);
}
//-------------------------------------------------------------------
public static void setPerRPGStatsPhase2(RoleplayingSystem rules, CarriedItemProcessor[] steps) {
PER_RPG_PHASE2_STEPS.put(rules, steps);
}
//-------------------------------------------------------------------
public static OperationResult validate(CarriedItem> model) {
return new OperationResult(true);
}
//-------------------------------------------------------------------
public static OperationResult> buildItem(T template, CarryMode mode, Lifeform charac, boolean strict, Decision...decisions) {
return buildItem(template, mode, null, charac, strict, decisions);
}
//-------------------------------------------------------------------
/**
* @param strict Don't ignore missing choices
*/
public static OperationResult> buildItem(T template, CarryMode mode, PieceOfGearVariant extends IVariantMode> variant, Lifeform charac, boolean strict, Decision...decisions) {
return buildItem(template, mode, variant, charac, strict, null, decisions);
}
//-------------------------------------------------------------------
/**
* @param strict Don't ignore missing choices
*/
public static OperationResult> buildItem(T template, CarryMode mode, PieceOfGearVariant extends IVariantMode> variant, Lifeform charac, boolean strict, IReferenceResolver context, Decision...decisions) {
// Create an instance to store results
CarriedItem ret = new CarriedItem(template, variant, mode);
ret.setUser(charac);
OperationResult> result = new OperationResult>(ret);
List validDecisions = new ArrayList<>();
List allChoices = new ArrayList<>(template.getChoices());
if (variant!=null) {
allChoices.addAll(variant.getChoices());
}
/*
* Add all decisions to CarriedItem. Validate each decision
*/
List expected = allChoices.stream().map(c -> c.getUUID()).collect(Collectors.toList());
logger.log(Level.DEBUG, "Go over all {0} decisions", decisions.length);
decisions:
for (Decision dec : decisions) {
if (dec.getChoiceUUID()==null) {
result.addMessage(new ToDoElement(Severity.STOPPER, "Internal error: missing UUID in decision "+dec.getValue()));
continue;
}
if (dec.getChoiceUUID()==PieceOfGear.VARIANT)
continue;
// Check if the referenced choice does exist
Choice choice = template.getChoice(dec.getChoiceUUID());
// If choice hasn't been found in the main object, try eventually selected variant
if (choice==null && variant!=null) {
choice = variant.getChoice(dec.getChoiceUUID());
}
if (choice==null) {
result.addMessage(new ToDoElement(Severity.STOPPER, "Internal error: choice "+dec.getChoiceUUID()+" does not exist in "+template.getId()));
continue;
}
expected.remove(dec.getChoiceUUID());
// Check the value of the decision
String[] options = choice.getChoiceOptions();
// if (logger.isLoggable(Level.WARNING))
// logger.log(Level.WARNING, "ToDo: validate ''{0}'' of type {1} with options {2}", dec.getValue(), choice.getChooseFrom(), Arrays.toString(options));
if (choice.getChoiceOptions()!=null) {
boolean found = false;
for (String opt : choice.getChoiceOptions()) {
if (opt.equals(dec.getValue())) {
// Decision matches element from option list
if (choice.isNegated()) {
// But those elements were marked as not allowed
result.addMessage(new ToDoElement(Severity.STOPPER, SELECTION_NOT_ALLOWED+": "+choice.getTypeReference()+"="+dec.getValue()));
continue decisions;
} else {
found = true;
validDecisions.add(dec);
}
break;
}
}
if (!found) {
logger.log(Level.WARNING, template.getId()+": Invalid decision "+dec.getValue()+" for "+choice.getTypeReference()+"/"+choice.getUUID());
}
} else {
// No choice options
ModifiedObjectType type = choice.getChooseFrom();
Object resolved = null;
try {
try {
resolved = Integer.parseInt(dec.getValue());
} catch (NumberFormatException e) {
resolved = type.resolve(dec.getValue());
}
} catch (ReferenceException e) {
logger.log(Level.ERROR, "In decision {0} of item {1}: {2}", dec, template, e.getMessage());
result.addMessage(new ToDoElement(Severity.WARNING, "Could not resolve "+dec.getValue()));
continue;
}
if (resolved==null) {
System.err.println("GearTool: Could not resolve "+dec.getValue()+" context="+context);
}
if (resolved==null && context!=null) {
resolved = context.resolveItem(dec.getValue());
}
if (resolved!=null) {
validDecisions.add(dec);
if (logger.isLoggable(Level.INFO)) {
logger.log(Level.INFO, template.getId()+": Valid decision "+dec.getValue()+" for "+type+"/"+choice.getUUID());
}
} else {
logger.log(Level.ERROR, "Valid decision {0} points to unknown object: {1}", choice.getUUID(), dec.getValue());
if (!strict) {
validDecisions.add(dec);
}
}
}
}
// For choices where decisions are missing, add the first decision
for (UUID uuid : expected) {
Choice choice = template.getChoice(uuid);
if (choice==null && variant!=null) {
choice = variant.getChoice(uuid);
}
if (choice==null) {
logger.log(Level.WARNING, "Expected choice "+uuid+" but template of "+template.getId()+" does not know about it");
throw new IllegalStateException("Expected choice "+uuid+" but template of "+template.getId()+" does not know about it");
}
if (choice.getChoiceOptions()!=null && choice.getChoiceOptions().length>0 && !strict) {
logger.log(Level.DEBUG, "Add first option {0} for choice {1}:{2}", choice.getChoiceOptions()[0], choice.getChooseFrom(), choice.getTypeReference());
validDecisions.add(new Decision(choice, choice.getChoiceOptions()[0]));
}
}
logger.log(Level.DEBUG, template.getId()+": Set decisions = "+validDecisions);
ret.setDecisions(validDecisions);
OperationResult> res = recalculate("", template.getReferenceType(), charac, ret, strict);
if (res.hasError()) {
res.getMessages().forEach(m -> result.addMessage(m));
}
if (res.get()!=null && !res.get().isEmpty()) {
logger.log(Level.DEBUG, "To Do: Add calculated character modifications to item {0}", ret);
logger.log(Level.DEBUG, "-2--{0}", ret.getIncomingModifications());
logger.log(Level.DEBUG, "-3--{0}", ret.getOutgoingModifications());
for (Modification mod : res.get()) {
logger.log(Level.DEBUG, "Add {0} {1}", mod, mod.getApplyTo());
if (mod.getApplyTo()==ApplyTo.DATA_ITEM || mod.getApplyTo()==null) {
ret.addIncomingModification(mod);
}
}
}
return result;
}
//-------------------------------------------------------------------
static CarriedItemProcessor[] concat(CarriedItemProcessor[] array1, CarriedItemProcessor[] array2) {
CarriedItemProcessor[] result = Arrays.copyOf(array1, array1.length + array2.length);
System.arraycopy(array2, 0, result, array1.length, array2.length);
return result;
}
//--------------------------------------------------------------------
protected static CarriedItemProcessor[] getSteps(CarriedItem> carried) {
RoleplayingSystem rules = null;
CarriedItemProcessor[] extra1 = null;
CarriedItemProcessor[] extra2 = null;
try {
if (!carried.getModifyable().getAssignedDataSets().isEmpty())
rules = carried.getModifyable().getAssignedDataSets().iterator().next().getRules();
} catch (Exception e) {
logger.log(Level.WARNING, "Error processing CarriedItem "+carried.getUuid()+": "+e);
throw e;
}
if (rules!=null) {
extra1= PER_RPG_PHASE1_STEPS.get(rules);
extra2= PER_RPG_PHASE2_STEPS.get(rules);
}
CarriedItemProcessor[] p1 = (extra1!=null)? concat(PHASE1_STEPS, extra1): PHASE1_STEPS;
CarriedItemProcessor[] p2 = (extra2!=null)? concat(PHASE2_STEPS, extra2): PHASE2_STEPS;
// logger.log(Level.WARNING, "Phase 1: ");
// for (CarriedItemProcessor p : p1) logger.log(Level.WARNING, " "+p.getClass());
// logger.log(Level.WARNING, "Phase 2: ");
// for (CarriedItemProcessor p : p2) logger.log(Level.WARNING, " "+p.getClass());
return concat(p1, p2);
}
public static OperationResult> recalculate(String indent, ModifiedObjectType refType, Lifeform user, CarriedItem> item) {
return recalculate(indent, refType, user, item, true);
}
//--------------------------------------------------------------------
/**
* - Copy resolved stats to attributes
* - Process decisions
* - Process modifications from "Modifications" (Permanent changes made to the base item)
* - Copy unresolved stats to attributes
*
* - Process modifications from accessories
*/
public static OperationResult> recalculate(String indent, ModifiedObjectType refType, Lifeform user, CarriedItem> item, boolean strict) {
// logger.log(Level.ERROR, indent+"recalculate {0} of {1}",item.getKey(), (user!=null)?user.getName():null);
if (item.getResolved()==null)
throw new DataErrorException(null, new ReferenceError(null, item.getTemplateID()));
String prefix = indent+item.getTemplateID()+": ";
item.reset();
logger.log(Level.DEBUG, prefix+"START:----------------"+item);
// Recalculate accessories
for (CarriedItem acc : item.getAccessories()) {
recalculate(indent+"", refType, user, acc);
}
OperationResult> unprocessed = new OperationResult(new ArrayList<>());
try {
for (CarriedItemProcessor step : getSteps(item)) {
if (logger.isLoggable(Level.TRACE))
logger.log(Level.TRACE, prefix+" run "+step.getClass().getSimpleName());
OperationResult> result = step.process(strict, refType, user, item, unprocessed.get());
if (result.hasError()) {
if (strict) {
logger.log(Level.WARNING, "Error recalculating item {0}: {1}",item.getUuid(), result.getMessages());
// return unprocessed;
}
} else {
// Replace previous data with current
unprocessed.set( result.get() );
}
// Copy all warnings to summarized object
// if (!result.getMessages().isEmpty()) {
// logger.log(Level.WARNING, "Step "+step+" added "+result.getMessages());
// }
unprocessed.getMessages().addAll(result.getMessages());
if (logger.isLoggable(Level.TRACE))
logger.log(Level.TRACE, prefix+" after "+step.getClass().getSimpleName()+" = "+unprocessed+" / "+item.getOutgoingModifications());
// logger.log(Level.TRACE, prefix+" after "+step.getClass().getSimpleName()+"\n"+item.dump());
}
logger.log(Level.DEBUG, prefix+" unprocessed = "+unprocessed);
logger.log(Level.DEBUG, prefix+" character = "+item.getOutgoingModifications());
logger.log(Level.DEBUG, prefix+" messages = "+unprocessed.getMessages());
unprocessed.get().forEach( tmp -> item.addIncomingModification(tmp));
// logger.log(Level.DEBUG, prefix+item.dump());
} catch (Exception e) {
logger.log(Level.ERROR, "Error recalculating item "+item.getKey()+" in "+user);
e.printStackTrace();
}
logger.log(Level.DEBUG, prefix+"STOP :----------------"+item);
item.setLastRecalculateResult(unprocessed);
return unprocessed;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy