Friya

Members
  • Content count

    102
  • Joined

  • Last visited

Community Reputation

77 Decent

1 Follower

About Friya

  • Rank
    Villager

Recent Profile Visitors

914 profile views
  1. Intermittent crashes or freezes are horrible, using a "game hoster" or not. Servers have died and been shut down for less. This will at at the very least help pinning down possible problems that may be introduced by a mod, a combination of mods or just plain old server bugs. I wrote this software to assist me in tracking down problems on a server that was getting intermittent freezes -- and it was rare enough that you want to be able to nail it when it first happens -- alas, I was not clairvoyant enough -- so here we have this mod -- a tad bigger than I thought it would become. I share it because I know I will rely on it in the future. It's a bit of a mish-mash of things (*), but I left it all in there as configurable options. It grew out of me eliminating causes of a problem. It was a server where I did not have any access, issue was not reproducible on a test server, and had an absolute crap-ton of mods. Read: I like a challenge (har har). Later on it it also grew into a tool to help me optimize the server code (or at least my behaviour around it). I have to say it's quite pleasant to be able to pinpoint and measure execution cost without modifying actual source code; I may actually start using a similar approach in non-hobby projects. Dumps If you have full control over your environment and have the technical abilities you may want to hook up some external tools to solve a lot of your problems. That said, this program can also output a stack and/or thread dump if it detects slow calls in a monitored area. It may even be easier to use this than other tools. Note that in many cases this will only point you in the direction of the problem. It could still mean you have a lot of work to do from there (i.e. chasing calls down the chain with more monitoring). The server is half-decent at tracking laggy calls itself (albeit a lot less granularity than what is possible using this), aaand provided the call actually finishes! The original usage of the monitor.* properties outlined in the config file below was to distinguish it from a complete freeze or something else (the problem was rare enough that I threw things on the wall to see what stuck). That said, you can monitor execution cost of any method on the server (to pinpoint strange hot areas) -- and attach possible interesting objects from that context ... to really nail it. To do this, use the monitor.* setting below. You can add as many of those as you may need. It's a pretty powerful tool and if I wasn't chasing a bug I'd start looking at a few spots I have taken notes of where I can optimize the actual WU server (optimizing -is- fun). Hard to reproduce exceptions Funnily enough, it turns out this is a great way to pin down intermittent exceptions. If you add a monitor to a call that takes place in a stack trace -- and wait (without much pain), if that call never finishes (i.e. it threw an exception), a warning will be printed in the log (options to include traces as well). To get the detail of which object is the offending one (say a specific creature), add an argument to the monitor (e.g. $0 for this). For a few special cases (like Zone), instead of just grabbing toString() of the object I output e.g. zone X/Y. I intend to add more humanly readable strings of object as I need them, but yeah, it's primarily toString() at the moment. Combine arguments to a monitor with a full thread dump on a slow call and any freezing or hanging problem should become evident rather quickly. Albeit rather spammy if you let it hang too long. A few warnings Monitoring methods will likely not play well with recursive methods, monitor those from the "outside" (never tried it) Monitoring methods that might be called by several threads simultaneously will get dodgy, no doubt (never tried it). Performance impact This mod is written with performance in mind, even if you choose to monitor tight loops it should not affect performance *too* much. The idea is that you can have this running on a live server and just wait for the problem to happen. That said, be aware that it does add a bit of overhead. And might be noticeable in hot tight loops. The cost of having something nice... Searching in spammy logs In order to find warnings in very spammy logs, search for "Hey Friya" (I kept it in there because I could) -- any offender will be tagged with those words. If you find too many "Hey Friya"'s, it probably means your slow call thresholds are too low -- set them higher. (*) the mish-mash: Dump methods calls in a method (in a format for easy copy/pasting for monitoring.* Log a brief version of data stream coming to and/or going from the server Logging of all actions created (read: new Action()), whether by NPC's or Players Slow mod detection; monitoring default mod hooks Monitor if main loop is still ticking Dump all classes modified by Javassist (I do not decompile them for you ) Dump thread info on slow running calls Monitor itself (! okay, this is a lie, but it will output a message every now and then to indicate this) A few more pointless monitoring options (they all sit in the same thread -- hence pointless) Storage of monitored methods executed since entering a hooked method (this helps determine the code path taken through a method) Various options to specify frequency at which things can happen Dump stack-trace on completion of a slow call Dump stack-trace of a monitored call that is still running ... and a few more things. Well, outta here. Cya on the flip side. Example of a properties file: Download latest version (install like any other server mod)
  2. It's funny that you mention it, was just sitting here talking to someone saying that it would only be at a certain speed. So it might only be happening in combination with mods. But yes, definitely -- mods affecting movement speed all over the place. The creature I have seen causing this is not in a 1x1, but I have been betting on it being in a corner of the enclosure. Thanks for taking a look, it does confirm that I'm not barking up the wrong tree.
  3. I've been chasing a bug in Wurm for a little while now. To a client it reveals itself like this when you try to log in: "Waiting for Steam authentication...", and it will hang there. There are probably situations where you see that message and it actually is true, but in the case of this bug it's just an unfortunate side-effect. The server is most likely hanging in a deadlock or an infinite loop. It will not accept any new connections and all connected clients will eventually disconnect due to timeouts. What you will see in the server log are some threads chugging along doing some work (outputting statistics and such), making it seem like it's kind of working. In the case I was asked to help track down, it was not, the mainthread is frozen (deadlocked/infinite loop). You have to restart your server in order to get things going again. So, off I went to find out where... and it SEEMS I have found it, but I'd like a few more eyeballs on it before I call it a day and pat myself on the back. It lies in the movement code of creatures and it's called from a bunch of different places. This code was introduced somewhere between 1.4 and 1.6 (I was out of the loop so don't have source for all version). It probably all came with the introduction of the "Creature Movement Changes" feature. In Creature.takeSimpleStep() we have: ... a little code ... for (int x = 0; x < mvs; ++x) { ... lots of code ... if ((lDiffTileX != 0 || lDiffTileY != 0) && !this.isGhost()) { ... even more code ... if (Features.Feature.CREATURE_MOVEMENT_CHANGES.isEnabled()) { this.turnTowardsTile((short)this.getTileX(), (short)this.getTileY()); this.rotateRandom(this.status.getRotation(), 45); x = 0; this.getStatus().setMoving(false); continue; } ... some code ... } ... even more code ... } ... even more code ... Setting x to 0 in the iteration here ... is potentially lethal. I am curious if anyone with access to the original source code (or author of the code) can shed some light on the intended behaviour and/or state that this can never cause an infinite loop due to the conditions set by: this.turnTowardsTile((short)this.getTileX(), (short)this.getTileY()); this.rotateRandom(this.status.getRotation(), 45); this.getStatus().setMoving(false); I have a hard time wrapping my head around the scenarios and the intentions (hence request for more eyeballs). That said even if it is guaranteed that we will not reset x every iteration, I have to say that this is also terribly nasty programming. If this is indeed causing spurious errors on your server a work-around for now: Disable the server feature "Creature Movement Changes" and it should fix the problem until a real patch can be released (since I don't know the intentions of this, I will not release a patch myself). But first and foremost, would like to hear some feedback on this as I have simply run out of patience waiting for the bug to manifest itself on a live server (it's rare enough). TLDR: for (int x = 0; x < mvs; ++x) { if(condition) { x = 0; continue; } } // we might never get here.
  4. That thread about cats!

    Was mucking about in the garden, went inside for a few minutes, come back out to find this...
  5. Hey MystLeissa, There were indeed some things that's moved around in Wurm. I did not spend much time testing things, but I did try bury and devour, both things should now work. Let me know if I'm a dirty stinking liar! The download is the same as in the original post. Edit: PS. I am sorry to hear about the all the vampires dying from soul feed. But hey, we all know they are the evil ones and the slayers are the good ones, right? Right?
  6. Real death

    Like you suspected, there is a faith requirement (50), deity requirement (BL / WL)... but also a skill requirement of 25 in soul strength or soul depth (depending on Deity). You also cannot have been a champion in the last six months.
  7. WU Server not Showing up for Public

    Try binding it to all your interfaces, mod here somewhere:
  8. Client mods stopped working

    Thanks for getting back with an explanation. This exception really got me curious. Glad it worked out :) oh and let me also give huge praise to Brash for always lurking and having good advice in this corner of the forum :)
  9. Client mods stopped working

    Well, okay then. Let's give it one more shot -- with reasoning then. The reason I am suggesting a forced repair of Wurm Unlimited is because a number of things could have gone wrong with your installation. This could be access permissions, diskspace, memory, corruption of a file, anything. So, try breaking your install and let Steam go over your installation -- it's probably the fastest way -- at least faster than trying everything what possibly could have gone wrong. The line in question that is throwing an exception in the modloader has no magic, it just wants to open client.jar. It failing suggests something out of the ordinary is wrong, and frankly it smells like an IO error to me (but no, I have not looked into the newFileSystem() method). Oh, and while running patcher.bat, make sure nothing has a file-lock on client.jar. If you are certain that you know that you've done everything right (and I do think you are doing everything right -- or at least have had no reason to think otherwise). But obviously something has changed on your system, if it worked yesterday.
  10. Client mods stopped working

    Well, if nothing is wrong, then I can obviously not help you. The fact that your mods are not working is because your modloader cannot patch your client; this is not a mod problem. The modloader is failing when attempting to access client.jar -- this is not normal, which is why I am asking about modloader, the client folder and your system. But if everything is okay in your Wurmlauncher folder...
  11. Client mods stopped working

    This was an interesting one... 1. Are you using the latest client modloader? If not, install that. 2. Do you have free diskspace on the disk where your client is installed? 3. Are you extremely memory constrained on your computer? (as in, little free memory left) 4. Have you tried rebooting your computer, and before doing anything else, run patcher.bat? If the answers to the above are all 'yes', try repairing your WU install in Steam. If Steam says everything is just hunky dory, break the installation by deleting say client.jar (also delete client-patched.jar for good measure)in your WurmLauncher folder, then ask Steam to repair it again. Umm, further questions if the above was not successful: - Can you give a screenshot of your Wurmlauncher folder?
  12. [Released] Priest Love (server mod)

    So, anyway... Apparently I left this mod unmaintained for too long... Note, bug: When mucking about on my test-server earlier today I noticed the detection of improved/failed spells was off, I'll post an update for that when time allows. If the wrong message is a bother, just disable the two options for now (that is: showPowerOnSuccessfulCast and showPowerOnFailedCast) . Changes: - Some refactoring and cleaning up - Drunken development bugfix (get player from persistence instead of logged-ins) - Configuration option: Output strength of cast to user when they successfully land - Configuration option: List of spells affected - Configuration option: useLegacyMessages (power in [...], caster in (...)) - Configuration option: showCasterNameBasedOnPower Example of "Show Power On Successful Cast": (you can toggle output of power for both successful and failed casts) Future of this mod: In the spirit of its name, at some point down the line I'll probably add... Support for free casts - high (and/or lucky) cast = caster gets a free cast (think rare) Support for caster names when it comes to runes (and *possibly* imbues) Ability to specify which spell to dispel on an item (other than fixing this annoyance, this is also relevant since you might want to purge names of other casters due to "reward system" below) Rare prayers (don't we all love them) is rewarded: on PVP server -- 3-5 instant casts; on PVE server -- 3-5 free casts A reward system for casters whose enchants are used. Still prototyping on this, the long-term idea is to at least make it viable to have a priest as (almost) a main and remove the need for "everyone is a priest". The ground work for this is done with this mod as it will start keeping track of who casted what. The configuration file contains some information, so pasting it in here for the details: # # Some love for the poor priests. # # I may or may not add more functionality over time. # # -- Friya, 2018 # classname=com.friya.wurmonline.server.priestlove.Mod classpath=priestlove.jar sharedClassLoader=true # # When priest successfully land a cast, they will see the strength of the cast in the event log. # E.g.: Your Courier cast landed with a power of 98. # # Set to false if you want don't want to ruin the surprise. # # Disable this behaviour by setting this to false. # showPowerOnSuccessfulCast=true # # Instead of just seeing that you failed to improve a cast, show just HOW unlucky you were. # showPowerOnFailedCast=true # # Personally I find the use of [ ] to convey the power of spells extremely ugly. But I can see # that it is of interest because of habits. # # That said, if you prefer ugly messages, set this to true. ;) # useLegacyMessages=false # # I like the idea of obscuring names on low-quality things in Wurm proper, but I do not agree # with how it's done. That said, I added it because it felt appropriate. # # You can turn behaviour off for spell-casters by setting this to false. # showCasterNameBasedOnPower=true # # Spells (their class names) that should be supported with names of the caster (typically only # spells that has a power and that can be cast on items). # # If you have custom spells living in the standard package (com.wurmonline.server.spells), simply # add their class name to the list below. # modify.spells.in.com.wurmonline.server.spells=Courier,Nimbleness,LurkerDeep,Opulence,CircleOfCunning,MindStealer,Bloodthirst,SharedPain,DarkMessenger,LurkerWoods,RottingTouch,Frostbrand,Nolocate,LurkerDark,WindOfAges,Venom,FlamingAura,WebArmour,BlessingDark,LifeTransfer # # For custom spells living outside of the default Wurm spells package, add the following # configuration line: # modify.spells.in.<name of the package>=<comma separated list of class names> # Make sure class has a doEffect() method with calls to addSpellEffect() and improvePower(). # # Example: # modify.spells.in.com.awkward.person.spells=SuperSpell,SubtleSpell # # (Note: this is untested, but should just work, I suppose -- if any trouble, just post in the # announcement thread). # Download link in the original post is updated.
  13. Poor priests, always neglected. Always alts. They grind their faith, they grind their channeling, no one will ever know. This will give credit where it's due. Enchants on items will reveal who did the cast. Example: https://i.imgur.com/bKIdXjA.png Given the rather vague name of this mod, I may, or may not, add functionality here. I have ideas, but if you have some as well, I'm all ears. Download *hic* (yes, very untested)
  14. [Released] GM Goto (server)

    # # A little mod to make my life easier; provides the #goto command for GM's. # I was SO fed up with having to use the wand. # That's it. # # Someone else probably already made a mod for this and I just did not know about it. # # Usage: Type #goto in any tab. # # Syntax: #goto <x y> # or #goto <deed name> # or #goto <player name> # # If the deed is multiple words, use quotes. E.g. #goto "Friya's Fantastic Fellowship" # If there is a deed called Friya and also a player with the same name, distinguish the two by doing #goto deed Friya or #goto player Friya # If going to coordinate, make sure it is within the map boundaries. # You cannot go to invisible GMs. # # - Friya, 2018 # Download And here's the source code for anyone wanting to do ... more. package com.friya.wurmonline.server.admin; import java.util.ArrayList; import java.util.StringTokenizer; import org.gotti.wurmunlimited.modloader.interfaces.PlayerMessageListener; import org.gotti.wurmunlimited.modloader.interfaces.WurmServerMod; import com.wurmonline.server.Players; import com.wurmonline.server.creatures.Communicator; import com.wurmonline.server.players.Player; import com.wurmonline.server.villages.NoSuchVillageException; import com.wurmonline.server.villages.Village; import com.wurmonline.server.villages.Villages; import com.wurmonline.server.zones.Zones; public class Mod implements WurmServerMod, PlayerMessageListener { @Override public boolean onPlayerMessage(Communicator com, String msg) { if(com.getPlayer().getPower() > 0) { // Verbose because I -may- want to add more GM commands. if(msg.startsWith("#goto")) { return cmdGoto(com, msg); } } return false; } private boolean cmdGoto(Communicator com, String cmd) { String[] tokens = translateCommandline(cmd); Location loc = null; if(tokens.length == 1) { tell(com, "Syntax:"); tell(com, " #goto <x y> or #goto <deed name> or #goto <player name>"); tell(com, "Examples:"); tell(com, " #goto 500 500"); tell(com, " #goto \"Friya's Home\""); tell(com, " #goto friya"); tell(com, "Notes:"); tell(com, " If the deed name is multiple words, use quotes. E.g. #goto \"Friya's Fantastic Fellowship\""); tell(com, " If there is a deed called Friya and also a player with the sane name, separate the two by doing #goto deed Friya or #goto player Friya"); tell(com, " If going to coordinate, make sure it is within the map boundaries."); tell(com, " You cannot go to invisible GMs."); return true; } if(tokens.length == 3) { if(isNumericUgly(tokens[1]) && isNumericUgly(tokens[2])) { // #goto x y loc = getCoordinateLocation(tokens[1], tokens[2]); } else if(tokens[1].equals("deed")) { // #goto deed loc = getDeedLocationByName(tokens[2]); } else if(tokens[1].equals("player")) { // #goto player loc = getPlayerLocationByName(tokens[2]); } } else if(tokens.length == 2) { // #goto <player name> loc = getPlayerLocationByName(tokens[1]); if(loc == null) { // #goto <deed name> loc = getDeedLocationByName(tokens[1]); } } if(loc == null || gotoTarget(com, loc) == false) { tell(com, "No idea how to go there... Typo? Coordinate is outside map? Target is invisible? Not a player? Already teleporting?"); } else { tell(com, "The fabric of space opens and you appear at " + loc.getName() + " ... or so you hope."); } return true; } private boolean gotoTarget(Communicator c, Location loc) { Player p = c.getPlayer(); p.setTeleportPoints((short)loc.getX(), (short)loc.getY(), loc.getLayer(), 0); if (p.startTeleporting()) { c.sendTeleport(false); p.teleport(); return true; } return false; } private Location getCoordinateLocation(String sx, String sy) { int x = Integer.parseInt(sx); int y = Integer.parseInt(sy); if(x < 1 || x > Zones.worldTileSizeX || y < 1 || y > Zones.worldTileSizeY) { return null; } return new Location(x + "x" + y, x, y, 0); } private Location getPlayerLocationByName(String name) { Player p = Players.getInstance().getPlayerOrNull(name.substring(0, 1).toUpperCase() + name.substring(1).toLowerCase()); // if target is an invisible GM, disallow going to them (caller will give a generic error) if(p == null || (p.getPower() > 0 && p.isVisible() == false)) { return null; } return new Location(p.getName(), p.getTileX(), p.getTileY(), p.getLayer()); } private Location getDeedLocationByName(String name) { Village d = null; try { d = Villages.getVillage(name); } catch (NoSuchVillageException e) { } if(d == null) { return null; } return new Location(d.getName(), d.getTokenX(), d.getTokenY(), 0); } /** * Crack a command line. * * Shamelessly lifted from another mod of mine which shamelessly lifted it from * Apache Commons. See https://commons.apache.org/proper/commons-exec/apidocs/src-html/org/apache/commons/exec/CommandLine.html * * @param toProcess the command line to process. * @return the command line broken into strings. * * An empty or null toProcess parameter results in a zero sized array. */ private String[] translateCommandline(String toProcess) { if (toProcess == null || toProcess.length() == 0) { return new String[0]; } final int normal = 0; final int inQuote = 1; final int inDoubleQuote = 2; int state = normal; final StringTokenizer tok = new StringTokenizer(toProcess, "\"\' ", true); final ArrayList<String> result = new ArrayList<String>(); final StringBuilder current = new StringBuilder(); boolean lastTokenHasBeenQuoted = false; while (tok.hasMoreTokens()) { String nextTok = tok.nextToken(); switch (state) { case inQuote: if ("\'".equals(nextTok)) { lastTokenHasBeenQuoted = true; state = normal; } else { current.append(nextTok); } break; case inDoubleQuote: if ("\"".equals(nextTok)) { lastTokenHasBeenQuoted = true; state = normal; } else { current.append(nextTok); } break; default: if ("\'".equals(nextTok)) { state = inQuote; } else if ("\"".equals(nextTok)) { state = inDoubleQuote; } else if (" ".equals(nextTok)) { if (lastTokenHasBeenQuoted || current.length() != 0) { result.add(current.toString()); current.setLength(0); } } else { current.append(nextTok); } lastTokenHasBeenQuoted = false; break; } } if (lastTokenHasBeenQuoted || current.length() != 0) { result.add(current.toString()); } if (state == inQuote || state == inDoubleQuote) { throw new RuntimeException("unbalanced quotes in " + toProcess); } return result.toArray(new String[result.size()]); } /** * Despite this using an exception for functionality, I am okay with it. It's executed rarely enough and definitely rare enough to trigger the exception. * * @param str * @return */ private boolean isNumericUgly(String str) { try { @SuppressWarnings("unused") double d = Double.parseDouble(str); } catch(NumberFormatException nfe) { return false; } return true; } private void tell(Communicator c, String msg) { c.sendNormalServerMessage(msg); } } /* ------------------------------------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------------------------------------- */ package com.friya.wurmonline.server.admin; class Location { private String _name; private int _x; private int _y; private int _layer = 0; Location(String name, int x, int y, int layer) { _name = name; _x = x; _y = y; _layer = layer; } String getName() { return _name; } int getX() { return _x; } int getY() { return _y; } public int getLayer() { return _layer; } }
  15. [Released] Server mod; Loot Tables

    That should just .... work. I use that quite extensively myself. I can't even come up with any idea of what could possibly go wrong? hm