99import java .util .Optional ;
1010
1111import org .gotti .wurmunlimited .modloader .ReflectionUtil ;
12+ import org .gotti .wurmunlimited .modloader .callbacks .CallbackApi ;
1213import org .gotti .wurmunlimited .modloader .classhooks .HookException ;
1314import org .gotti .wurmunlimited .modloader .classhooks .HookManager ;
1415import org .gotti .wurmunlimited .modloader .classhooks .InvocationHandlerFactory ;
1819import com .wurmonline .server .creatures .Creature ;
1920import com .wurmonline .server .creatures .CreatureTemplate ;
2021import com .wurmonline .server .creatures .Traits ;
22+ import com .wurmonline .shared .util .StringUtilities ;
2123
2224import javassist .CannotCompileException ;
2325import javassist .ClassPool ;
@@ -66,11 +68,11 @@ public String getTraitName() {
6668 return name ();
6769 }
6870 }
69-
71+
7072 private static List <ModCreature > creatures = new LinkedList <>();
7173 private static Map <Integer , ModCreature > creaturesById = new HashMap <>();
7274 private static boolean inited ;
73-
75+
7476 public static void init () {
7577 if (inited )
7678 return ;
@@ -159,21 +161,19 @@ public Object invoke(Object proxy, Method method, Object[] args) throws Throwabl
159161 });
160162
161163 try {
164+ /**
165+ * Replace call for Traits.getTraitString() with a call to GmSetTraitsCallbacks.getTraitString()
166+ * where custom colors and custom traits are checked checked first before falling back to Traits.getTraitString()
167+ */
168+ CtClass ctGmSetTraits = classPool .get ("com.wurmonline.server.questions.GmSetTraits" );
169+ HookManager .getInstance ().addCallback (ctGmSetTraits , "modcreatures" , new GmSetTraitsCallbacks ());
170+
162171 // com.wurmonline.server.questions.GmSetTraits.sendQuestion()
163- classPool . get ( "com.wurmonline.server.questions.GmSetTraits" ) .getMethod ("sendQuestion" , "()V" ).instrument (new ExprEditor () {
172+ ctGmSetTraits .getMethod ("sendQuestion" , "()V" ).instrument (new ExprEditor () {
164173 @ Override
165174 public void edit (MethodCall m ) throws CannotCompileException {
166175 if (m .getClassName ().equals ("com.wurmonline.server.creatures.Traits" ) && m .getMethodName ().equals ("getTraitString" )) {
167- StringBuffer buffer = new StringBuffer ();
168- buffer .append ("{\n " );
169- buffer .append ("String name = null;\n " );
170- buffer .append ("org.gotti.wurmunlimited.modsupport.creatures.ModCreature c = org.gotti.wurmunlimited.modsupport.creatures.ModCreatures.getModCreature(creature.getTemplate().getTemplateId());\n " );
171- for (CustomTrait customTrait : CustomTrait .values ()) {
172- buffer .append ("if (c != null && $1 == " + customTrait .getTraitNumber () + ") { name = c.getTraitName(" + customTrait .getTraitNumber () + "); $_ = name != null ? name : \" \" ; } else \n " );
173- }
174- buffer .append ("$_ = $proceed($$);\n " );
175- buffer .append ("}" );
176- m .replace (buffer .toString ());
176+ m .replace ("$_ = modcreatures.getTraitString(creature, $1);" );
177177 }
178178 }
179179 });
@@ -184,24 +184,32 @@ public void edit(MethodCall m) throws CannotCompileException {
184184
185185 try {
186186 final CtClass ctCreature = classPool .get ("com.wurmonline.server.creatures.Creature" );
187+ HookManager .getInstance ().addCallback (ctCreature , "modcreatures" , new CreatureCallbacks ());
187188
188189 {
189190 // com.wurmonline.server.creatures.Creature.getModelName()
190- String code = "{ String name = org.gotti.wurmunlimited.modsupport.creatures.ModCreatures .getModelName($0); if (name != null) { return name; }; }" ;
191+ String code = "{ String name = modcreatures .getModelName($0); if (name != null) { return name; }; }" ;
191192 ctCreature .getMethod ("getModelName" , Descriptor .ofMethod (classPool .get ("java.lang.String" ), new CtClass [0 ])).insertBefore (code );
192193 }
193194
194195 {
195196 // com.wurmonline.server.creatures.Creature.getColourName()
196- String code = "{ String colour = org.gotti.wurmunlimited.modsupport.creatures.ModCreatures .getColourName($0); if (colour != null) { return colour; }; }" ;
197+ String code = "{ String colour = modcreatures .getColourName($0); if (colour != null) { return colour; }; }" ;
197198 ctCreature .getMethod ("getColourName" , Descriptor .ofMethod (classPool .get ("java.lang.String" ), new CtClass [0 ])).insertBefore (code );
198199 }
199200
201+ {
202+ // com.wurmonline.server.creatures.Creature.getColourName(int trait)
203+ String code = "{ String colour = modcreatures.getColourName($0, $1); if (colour != null) { return colour; }; }" ;
204+ ctCreature .getMethod ("getColourName" , Descriptor .ofMethod (classPool .get ("java.lang.String" ), new CtClass [] { classPool .get ("int" ) })).insertBefore (code );
205+ }
206+
207+
200208 ctCreature .getMethod ("die" , "(ZLjava/lang/String;)V" ).instrument (new ExprEditor () {
201209 @ Override
202210 public void edit (FieldAccess f ) throws CannotCompileException {
203211 if (f .getClassName ().equals ("com.wurmonline.server.creatures.CreatureTemplate" ) && f .getFieldName ().equals ("isHorse" )) {
204- f .replace ("{ String name = org.gotti.wurmunlimited.modsupport.creatures.ModCreatures .getTraitName(this); if (name != null) { corpse.setDescription(name); $_ = false; } else { $_ = $proceed($$); } }" );
212+ f .replace ("{ String name = modcreatures .getTraitName(this); if (name != null) { corpse.setDescription(name); $_ = false; } else { $_ = $proceed($$); } }" );
205213 }
206214 }
207215
@@ -211,7 +219,7 @@ public void edit(FieldAccess f) throws CannotCompileException {
211219 @ Override
212220 public void edit (MethodCall m ) throws CannotCompileException {
213221 if (m .getClassName ().equals ("com.wurmonline.server.creatures.Traits" ) && m .getMethodName ().equals ("calcNewTraits" ) && m .getSignature ().equals ("(DZJJ)J" )) {
214- m .replace ("$_ = org.gotti.wurmunlimited.modsupport.creatures.ModCreatures# calcNewTraits($1, $2, this, father);" );
222+ m .replace ("$_ = modcreatures. calcNewTraits($1, $2, this, father);" );
215223 }
216224 }
217225 });
@@ -224,15 +232,7 @@ public void edit(MethodCall m) throws CannotCompileException {
224232 public void edit (MethodCall m ) throws CannotCompileException {
225233 if (m .getClassName ().equals ("com.wurmonline.server.creatures.Creature" ) && m .getMethodName ().equals ("isHorse" )) {
226234 StringBuffer code = new StringBuffer ();
227-
228- code .append ("{" );
229- code .append ("if (org.gotti.wurmunlimited.modsupport.creatures.ModCreatures.hasTraits($0.getTemplate().getTemplateId())) { " );
230- code .append ("org.gotti.wurmunlimited.modsupport.creatures.ModCreatures.assignTraits($0);" );
231- code .append ("$_ = false;" );
232- code .append ("} else {" );
233- code .append ("$_ = $proceed($$);" );
234- code .append ("}" );
235- code .append ("}" );
235+ code .append ("$_ = !modcreatures.assignTraits($0) && $proceed($$);" );
236236 m .replace (code .toString ());
237237 }
238238 }
@@ -248,7 +248,7 @@ public void edit(MethodCall m) throws CannotCompileException {
248248
249249 inited = true ;
250250 }
251-
251+
252252 public static void addCreature (ModCreature creature ) {
253253 if (!inited ) {
254254 throw new RuntimeException ("ModCreatures was not initied" );
@@ -346,4 +346,79 @@ public static long calcNewTraits(final double breederSkill, final boolean inbred
346346
347347 return modMother .calcNewTraits (breederSkill , inbred , mothertraits , fathertraits );
348348 }
349+
350+ private static class GmSetTraitsCallbacks {
351+ @ CallbackApi
352+ public String getTraitString (Creature creature , int trait ) {
353+ ModCreature modCreature = ModCreatures .getModCreature (creature .getTemplate ().getTemplateId ());
354+ if (modCreature != null && isCustomTrait (trait )) {
355+ String colorName = modCreature .getColourName (trait );
356+ if (colorName != null )
357+ return StringUtilities .raiseFirstLetterOnly (colorName );
358+
359+ String traitName = modCreature .getTraitName (trait );
360+ if (traitName != null )
361+ return traitName ;
362+ }
363+
364+ return Traits .getTraitString (trait );
365+ }
366+ }
367+
368+ private static class CreatureCallbacks {
369+
370+ @ CallbackApi
371+ public String getModelName (Creature creature ) {
372+ return ModCreatures .getModelName (creature );
373+ }
374+
375+ @ CallbackApi
376+ public String getColourName (Creature creature ) {
377+ return ModCreatures .getColourName (creature );
378+ }
379+
380+ @ CallbackApi
381+ public String getColourName (Creature creature , int trait ) {
382+ ModCreature c = ModCreatures .getModCreature (creature .getTemplate ().getTemplateId ());
383+ if (c != null && c .hasTraits ()) {
384+ // The creature has traits. Return the color name or an empty string
385+ String color = c .getColourName (trait );
386+ if (color != null ) {
387+ return color ;
388+ }
389+ return "" ;
390+ }
391+ return null ;
392+ }
393+
394+
395+ @ CallbackApi
396+ public String getTraitName () {
397+ return ModCreatures .getTraitName (null );
398+ }
399+
400+ @ CallbackApi
401+ public boolean hasTraits (int templateId ) {
402+ return ModCreatures .hasTraits (templateId );
403+ }
404+
405+ @ CallbackApi
406+ public long calcNewTraits (final double breederSkill , final boolean inbred , final Creature mother , final Creature father ) {
407+ return ModCreatures .calcNewTraits (breederSkill , inbred , mother , father );
408+ }
409+
410+ /**
411+ * Assign traits if the creature has custom traits.
412+ * @return true if the creature has custom traits, false otherwise
413+ */
414+ @ CallbackApi
415+ public boolean assignTraits (Creature creature ) {
416+ if (ModCreatures .hasTraits (creature .getTemplate ().getTemplateId ())) {
417+ ModCreatures .assignTraits (creature );
418+ return true ;
419+ }
420+ return false ;
421+ }
422+
423+ }
349424}
0 commit comments