Skip to content

Instantly share code, notes, and snippets.

@Joedobo27
Created May 24, 2017 21:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Joedobo27/089c17c7f691f6d6ffb03577ad042ed8 to your computer and use it in GitHub Desktop.
Save Joedobo27/089c17c7f691f6d6ffb03577ad042ed8 to your computer and use it in GitHub Desktop.
package com.joedobo27.simplefoodbonuses;
import javassist.*;
import javassist.bytecode.Descriptor;
import javassist.expr.ExprEditor;
import javassist.expr.MethodCall;
import org.gotti.wurmunlimited.modloader.classhooks.HookManager;
import org.gotti.wurmunlimited.modloader.interfaces.Configurable;
import org.gotti.wurmunlimited.modloader.interfaces.PreInitable;
import org.gotti.wurmunlimited.modloader.interfaces.WurmServerMod;
import java.util.Arrays;
import java.util.Objects;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
public class SimpleFoodBonusesMod implements WurmServerMod, PreInitable, Configurable{
static final Logger logger = Logger.getLogger(SimpleFoodBonusesMod.class.getName());
private static boolean versionCompliant = false;
private static final String[] STEAM_VERSION = new String[]{"1.3.1.3"};
@Override
public void configure(Properties properties) {
if (Arrays.stream(STEAM_VERSION)
.filter(s -> Objects.equals(s, properties.getProperty("steamVersion", null)))
.count() > 0)
versionCompliant = true;
else
logger.log(Level.WARNING, "WU version mismatch. Your " + properties.getProperty(" steamVersion", null)
+ "version doesn't match one of BulkOptionsMod's required versions " + Arrays.toString(STEAM_VERSION));
}
@Override
public void preInit() {
if (!versionCompliant)
return;
int[] successes = new int[6];
int[] result;
result = modifyHungerBytecodeChange();
System.arraycopy(result,0, successes, 0, 1);
result = drinkBytecodeChange();
System.arraycopy(result,0, successes, 1, 2);
result = addTimedAffinityFromBonusBytecodeChange();
System.arraycopy(result,0, successes, 3, 1);
result = eatBytecodeChange();
System.arraycopy(result,0, successes, 4, 1);
result = alterSkillBytecodeChange();
System.arraycopy(result,0, successes, 5, 1);
evaluateChangesArray(successes);
}
/**
* edit Skill.alterSkill() so nutritional bonus is 0 to 15% instead of 0 to 5%. Instead of a complicated affinity system
* just add up to 10% more bonus from nutrition level.
* was-
* staminaMod += Math.max(player2.getStatus().getNutritionlevel() / 10.0f - 0.05f, 0.0f);
* becomes-
* staminaMod += Math.max(player2.getStatus().getNutritionlevel() * 5 / 33, 0.0f);
*
* note, 0.99 nutrition needs to be 0.15 bonus. 0.15 / 0.99 is repeating .15 or 5/33. thus, multipliing by 5/33 will
* make generate a value from 0 to 15%.
*/
private int[] alterSkillBytecodeChange() {
final int[] successes = {0};
try {
CtClass skillCt = HookManager.getInstance().getClassPool().get("com.wurmonline.server.skills.Skill");
CtClass returnType = CtPrimitiveType.voidType;
CtClass[] params = {
CtPrimitiveType.doubleType, CtPrimitiveType.booleanType, CtPrimitiveType.floatType, CtPrimitiveType.booleanType,
CtPrimitiveType.doubleType
};
CtMethod alterSkillCt = skillCt.getDeclaredMethod("alterSkill", params);
alterSkillCt.instrument(new ExprEditor() {
@Override
public void edit(MethodCall methodCall) throws CannotCompileException {
if (Objects.equals(methodCall.getMethodName(), "max") && methodCall.getLineNumber() == 1556) {
methodCall.replace("{ $1 = player.getStatus().getNutritionlevel() * 5 / 33; $_ = $proceed($$); }");
successes[0] = 1;
}
}
});
}catch (NotFoundException | CannotCompileException e) {
logger.warning(e.getMessage());
}
return successes;
}
/**
* edit MethodsItems.eat() so food is never too hot to eat.
* By preventing getTemperature from returning values greater then 2500 food is never too hot.
*/
private int[] eatBytecodeChange() {
final int[] successes = {0};
try {
CtClass methodItemsCt = HookManager.getInstance().getClassPool().get("com.wurmonline.server.behaviours.MethodsItems");
CtClass[] params = {
HookManager.getInstance().getClassPool().get("com.wurmonline.server.behaviours.Action"),
HookManager.getInstance().getClassPool().get("com.wurmonline.server.creatures.Creature"),
HookManager.getInstance().getClassPool().get("com.wurmonline.server.items.Item"),
CtPrimitiveType.floatType
};
CtMethod eatCt = methodItemsCt.getDeclaredMethod("eat", params);
eatCt.instrument(new ExprEditor() {
@Override
public void edit(MethodCall methodCall) throws CannotCompileException {
if (Objects.equals(methodCall.getMethodName(), "getTemperature")) {
methodCall.replace("$_ = $_ > 2500 ? 2500 : $_;");
successes[0] = 1;
}
}
});
}catch (NotFoundException | CannotCompileException e) {
logger.warning(e.getMessage());
}
return successes;
}
/**
* edit AffinitiesTimed.addTimedAffinityFromBonus() to make it so getBonus() returns -1 and disables affinity creation.
*
* was-
* final int ibonus = item.getBonus();
* becomes-
* final int ibonus = -1;
*/
private int[] addTimedAffinityFromBonusBytecodeChange() {
final int[] successes = {0};
try {
CtClass AffinitiesTimedCt = HookManager.getInstance().getClassPool().get("com.wurmonline.server.skills.AffinitiesTimed");
CtClass returnType = CtPrimitiveType.voidType;
CtClass[] paramTypes = {
HookManager.getInstance().getClassPool().get("com.wurmonline.server.creatures.Creature"),
CtPrimitiveType.intType,
HookManager.getInstance().getClassPool().get("com.wurmonline.server.items.Item")
};
CtMethod addTimedAffinityFromBonusCt = AffinitiesTimedCt.getMethod("addTimedAffinityFromBonus", Descriptor.ofMethod(returnType, paramTypes));
addTimedAffinityFromBonusCt.instrument(new ExprEditor() {
@Override
public void edit(MethodCall methodCall) throws CannotCompileException {
if (Objects.equals(methodCall.getMethodName(), "getBonus")) {
methodCall.replace("$_ = -1;");
successes[0] = 1;
}
}
});
}catch (NotFoundException | CannotCompileException e) {
logger.warning(e.getMessage());
}
return successes;
}
/**
* edit MethodsItems.modifyHunger() so food complexity has no effect.
* was-
* float complexity = food.getFoodComplexity() * 50.0f;
* becomes-
* float complexity = 2.0f * 50.0f;
* getFoodComplexity() would return 2 if the food had 10 stages and 30 ingredients which would be one of the most
* complex or difficult meals.
*/
private int[] modifyHungerBytecodeChange() {
final int[] successes = {0};
try {
CtClass methodItemsCt = HookManager.getInstance().getClassPool().get("com.wurmonline.server.behaviours.MethodsItems");
CtMethod modifyHungerCt = methodItemsCt.getDeclaredMethod("modifyHunger");
modifyHungerCt.instrument(new ExprEditor() {
@Override
public void edit(MethodCall methodCall) throws CannotCompileException {
if (Objects.equals(methodCall.getMethodName(), "getFoodComplexity")) {
methodCall.replace("$_ = 2.0;");
successes[0] = 1;
}
}
});
}catch (NotFoundException | CannotCompileException e) {
logger.warning(e.getMessage());
}
return successes;
}
/**
* edit MethodsItems.drink() so food complexity has no effect.
* was-
* final float complexity = drink.getFoodComplexity() * 20.0f;
* becomes-
* float complexity = 2.0f * 20.0f;
* getFoodComplexity() would return 2 if the drink had 10 stages and 30 ingredients which would be one of the most
* complex or difficult drinks.
*
* edit MethodsItems.drink() so drinks are never too hot to drink.
* By making sure getTemperature returns values less then 300 drinks are never too hot.
*
*/
private int[] drinkBytecodeChange() {
final int[] successes = {0,0};
try {
CtClass methodItemsCt = HookManager.getInstance().getClassPool().get("com.wurmonline.server.behaviours.MethodsItems");
CtMethod drinkCt = methodItemsCt.getDeclaredMethod("drink");
drinkCt.instrument(new ExprEditor() {
@Override
public void edit(MethodCall methodCall) throws CannotCompileException {
if (Objects.equals(methodCall.getMethodName(), "getFoodComplexity")) {
methodCall.replace("$_ = 2.0;");
successes[0] = 1;
}
else if (Objects.equals(methodCall.getMethodName(), "getTemperature")) {
methodCall.replace("$_ = 299;");
successes[1] = 1;
}
}
});
}catch (NotFoundException | CannotCompileException e) {
logger.warning(e.getMessage());
}
return successes;
}
private static void evaluateChangesArray(int[] ints) {
boolean changesSuccessful = Arrays.stream(ints).noneMatch(value -> value == 0);
if (changesSuccessful) {
logger.log(Level.INFO, "simple food bonuses changes SUCCESS");
} else {
logger.log(Level.INFO, "simple food bonuses changes FAILURE");
logger.log(Level.FINE, Arrays.toString(ints));
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment