Sign in to follow this  
joedobo

[WIP] Various Farming changes, like crops don't turn to weeds.

Recommended Posts

For all these modification I'm just going to tell you what to change in the server.jar file. You'll need to make the changes, compile the classes and finally use those classes to replace classes in the jar file. If this means the post don't qualify as mods feel free to move the post elsewhere.


 


1. Farm crops don't turn to weeds.


 


in the server's Terraforming.class (com.wurmonline.server.behaviours) there is a method like:


static boolean growFarm(Creature performer, int tile, int tilex, int tiley, boolean onSurface)


 


Find this and change that 7 to 6. This will stop the code from advancing crop age beyond the last stage of ripe.



if(tileAge < 7) {
int crop = data & 15;

Secondly, in the server's  CropTilePoller.class (com.wurmonline.server.zones) there is a method like:


public static void checkForFarmGrowth(int tile, int tilex, int tiley, byte type, byte aData, MeshIO currentMesh, boolean pollingSurface) 

 

fnd this and change that 7 to 6. This will stop the code from advancing crop age beyond the last stage of ripe.



} else if(tileAge < 7) {
if((tileAge == 5 || tileAge == 6) && Server.rand.nextInt(3) < 2) {
return;
}

2. Farm indoors.


 


In the server's cropTilePoller.class (com.wurmonline.server.zones) and under the checkForFarmGrowth method is something that looks likes this:



++tileAge;
VolaTile tempvtile1 = Zones.getOrCreateTile(tilex, tiley, pollingSurface);
if(tempvtile1.getStructure() != null) {
currentMesh.setTile(tilex, tiley, Tiles.encode(Tiles.decodeHeight(tile),
Tile.TILE_DIRT.id, (byte)0));
Server.modifyFlagsByTileType(tilex, tiley, Tile.TILE_DIRT.id);
} else {
currentMesh.setTile(tilex, tiley, Tiles.encode(Tiles.decodeHeight(tile), Tile.TILE_FIELD.id,
(byte)((tileAge << 4) + crop & 255)));
Server.modifyFlagsByTileType(tilex, tiley, Tile.TILE_FIELD.id);
if(logTilePolling) {
logger.log(Level.INFO, "Changed the tile");
}
}

replace all that with the following to get rid of the code that turns tiles to dirt if they are in a structure.



++tileAge;
currentMesh.setTile(tilex, tiley, Tiles.encode(Tiles.decodeHeight(tile), Tile.TILE_FIELD.id,
(byte)((tileAge << 4) + crop & 255)));
Server.modifyFlagsByTileType(tilex, tiley, Tile.TILE_FIELD.id);
if(logTilePolling) {
logger.log(Level.INFO, "Changed the tile");
}

Secoundly, in the server's TileDirtBehviour.class (com.wurmonline.server.behaviours) and under the method Action are a few lines that I commented out. This is so you can do sow actions inside a building.



//VolaTile vtile = Zones.getOrCreateTile(tilex, tiley, onSurface);
//if(vtile != null && vtile.getStructure() != null) {
// performer.getCommunicator().sendNormalServerMessage(
// "The " + source.getName() + " would never grow inside.");
// return true;
//}

3. Buff farm yields


in the server's Terraforming.class (com.wurmonline.server.behaviours) and under the harvest method is a line kinda like the one on top and what I changed is on the bottom:



short bonusYield = (short)((int)((float)resource / div / 1.5F));

short bonusYield = (short)((int)((float)resource / div / 1.5F) + 2 );

This add 2 more crops to all outcomes.


 


4. Dry land rice.


coming soon.


 


5. Adding more farmable crops.


No estimates here, but i really want to do this so i'll figure it out eventually.


 


 


Edited by joedobo
  • Like 2

Share this post


Link to post
Share on other sites

I'm assuming extended period would be maybe a week if crops get ripe in a day or even a month. There probably are performance issues with leaving crop tiles at ripe and server doing growth checks that never succeed.


 


okay so an extended period of time...Crop growth works kinda like a simple counter and with WU settings we control how frequently the counter increments.


 


Here is the code that changes the tile. The important part for me are those bitwise operations at the end and the variable tileAge. tileAge varaible is the growth counter and when it gets to 7 the crop turns to weeds. Somehow I'd need to delay incrementing tileAge to 7 for the extended duration. 



currentMesh.setTile(tilex, tiley, Tiles.encode(Tiles.decodeHeight(tile), Tile.TILE_FIELD.id, (byte)((tileAge << 4) + crop & 255)));

I'm not sure how best to do it. Just brainstorming here...import time tools, and a way to send a timestamp to DB for that tile, add a method to fetch the timestamp and measure elapsed time. If its too much set tileAge to 7 and turn to weeds. 


Share this post


Link to post
Share on other sites

Whats the max size of the byte/bit/nibble they are using for tileAge? I'm not very familiar with byte operations beyond very basic flag techniques.


Share this post


Link to post
Share on other sites

else if (tileAge < 7) {

if ((tileAge == 5 || tileAge == 6) && Server.rand.nextInt(3) < 2) {

return;

}

Or make a copy of this (tileAge<7) and exit the check growth method more frequently, but it'd still be random.  

Edited by Glycian

Share this post


Link to post
Share on other sites

I know nothing about bitwise stuff. That's why I'd want to keep using the 1 to 7 numbers. For some reason trying to modify data storage architecture doesn't sound like fun. 


 


I'm guessing you can see the result of that bitwise calculation is cast to byte. Variables "tileAge" and "crop" are declared as int.

Share this post


Link to post
Share on other sites

but it'd still be random. 

a RNG algorithm might work. Something like this maybe?

} else if (tileAge == 6 && random.nextFloat() < 0.006) {

// 0.006 = 1h / 168 h. a week is 168 hours.

// if growth check was 1h then crops would be ripe in about 5 hours and

// would on average trun to weeds 6-1/2 days later.

++tileAge;

currentMesh.setTile(tilex, tiley, Tiles.encode(Tiles.decodeHeight(tile), Tile.TILE_FIELD.id,

(byte)((tileAge << 4) + crop & 255)));

Server.modifyFlagsByTileType(tilex, tiley, Tile.TILE_FIELD.id);

if(logTilePolling) {

logger.log(Level.INFO, "Changed the tile");

}

Players.getInstance().sendChangedTile(tilex, tiley, pollingSurface, false);

}

The main issue with RNG is its unpredictable nature and influence on players.

 

 

edit...

I think the probability model with this is wrong. I'll work on it more tomorrow.

edit

fixed RNG

Edited by joedobo

Share this post


Link to post
Share on other sites

What about farming in caves? Would something like that be possible?


Edited by atazs

Share this post


Link to post
Share on other sites

nothing is "impossible" :P


 


but then again, why would you want to farm in a cave?... Only realistic things to farm there are mushrooms :P


Share this post


Link to post
Share on other sites

I am so, so happy this exists, especially crops never turning into weeds as this is exactly what I was looking for, to have farming villages with never-dying crops as decoration in creative mode. This is awesome, thank you! :D


 


Though I had a request. If it's something that's possible, could you, or someone else who knows this stuff, maybe make some really coding-noob-friendly version of the undying crops? I don't know anything about coding so I don't know if it's even possible or if that's something everyone has to do for themselves, but I find myself intimidated by the idea of compiling classes and replacing classes since I don't know what that means or entails. If it's not possible, or hugely time-consuming or something, then I can find out of course, but I thought I'd ask in case someone can do it in a fast and easy way. If not, I will find out and try to get it to work myself, but going into this kind of stuff with no coding experience I think is intimidating for most people... 


Share this post


Link to post
Share on other sites

I am so, so happy this exists, especially crops never turning into weeds as this is exactly what I was looking for, to have farming villages with never-dying crops as decoration in creative mode. This is awesome, thank you! :D

 

Though I had a request. If it's something that's possible, could you, or someone else who knows this stuff, maybe make some really coding-noob-friendly version of the undying crops? I don't know anything about coding so I don't know if it's even possible or if that's something everyone has to do for themselves, but I find myself intimidated by the idea of compiling classes and replacing classes since I don't know what that means or entails. If it's not possible, or hugely time-consuming or something, then I can find out of course, but I thought I'd ask in case someone can do it in a fast and easy way. If not, I will find out and try to get it to work myself, but going into this kind of stuff with no coding experience I think is intimidating for most people... 

 

Unless you edit the code and compile it yourself, you won't retain previous modifications to the server files (unless all are in separate class files and you just replace them separately).  So if you want an easy way for undying crops (someone else compiles it for you), you would have to overwrite any existing server.jar modifications and replace it with the server.jar with the undying crops mod. 

 

I think calling the disband settlement sound file upon reaching tileAge 7 would be an acceptable alternative :)

Edited by Glycian

Share this post


Link to post
Share on other sites

Sia, the short answer is WU wasn't designed to be modded. Now, we [the players] have just jump right in and are wading through the problems of figuring out how to best go about modding. Specifically, in the case of no-weeds, the variables that need to be changed are hard coded constants.  


 


There are problems with sharing compiled classes. One of them is that a lot of mods will change the server's Terraforming.class. One modders compiled version of that class will replace another modders work. This problem exists for all class actualy but it's expecialy bad in Terraforming.class as that has many functions players will want to change.


The work to compile all possible combinations of different alteration is too much. Another is It makes it more complicated for me to share a compiled class that has say just the no weeds change. My Terraforming.class has other changes in it.


 


 


Sia, I don't expect you to know the answers to the following but I want to bring it up again because we really need to find a solution to the problem seen here.


I've mentioned a few time now an idea of a standardized modders server and client. These files would be altered versions that by default they run basic WU but with reflection tools modders can enable different function. In the case of no-weeds we might add something like the following to the modding jar files. I"m a total noob so I don't know if this is a good idea of not.



private static int maxCropAge = 7
private static float extendedDurationWeedsChance = 0.0F
.
.
.
if(tileAge < maxCropAge) {
// stuff
}

if(tileAge == maxCropAge && extendedDurationWeedsChance != 0.0F) {
// RNG code to change to weeds. RNG chance is low and on average will ripe crops
//to weeds have a much longer duration then it took to get to ripe.
}

note..Is it it right to use constants like that? It seems strange to me the constructor in that class isn't used at all.


Share this post


Link to post
Share on other sites

I'm currently testing the one change to CropTilePoller for weed prevention with my modloader (yeah I'm shamelessly plugging that thing)

The changes to Terraforming.java are only preventing GMs from overgrowing the fields so it's actually just that very simple change related to CropTilePoller.java.

https://github.com/ago1024/WurmServerModLauncher/releases/tag/v0.5

This is very good news! Now I just got to read that code another 100 times or more and spend countless hours research why it works...oh to be a self-taught noob.  I appreciate the comments in the code a lot! 

Share this post


Link to post
Share on other sites

Joedobo,


 


Would a "while" or "for" loop work to count increments steps... and possibly store the count variable for each tile somewhere?


 


IE;


 


crops grow to 6 (ripe) based on increment and Server step frequency


while $variable is < 100, crop growth stage = 6


  $variable ++


once out of the while loop ($variable = 101)


crop growth stage = 7


 


anyone wanting to extend/reduce the "ripe" period would only need to alter 100 to something bigger or smaller.  0 would be default.


Share this post


Link to post
Share on other sites

Jarosz, that would create a blocking loop and essentially freeze the thread running the loop until it finished.


Share this post


Link to post
Share on other sites

Joedobo,

 

Would a "while" or "for" loop work to count increments steps... and possibly store the count variable for each tile somewhere?

 

 

As MacrosBlack said the loop approach won't work. Another way to achieve the same thing would be a variable that is incremented by 1 every time checkForFarmGrowth method is ran. But the class is static so you can't create a instanced data object for every farm tile. I'm thinking you wouldn't want to anyway to minimize memory use. In this case using the database to store such a counter for each tile sounds better. The method's original design is basically just that, fetch a counter from data base, do stuff with that counter, and store a new value if changes need to be made.

 

 

Although, I still like the RNG algorithm approach. I'm thinking for each call to checkForFarmGrowth() method when tileAge is 6 there would be a 0.006 chance to go to weeds. I like the RNG way because its easy to code, uses little memory and doesn't require any DB or file-storage system. I arrived at 0.006 by 1 hr / 168 hr. a week has 168 hours. Using a 1 hour growth timer option, crops would be ripe in about 5 hours and would on average turn to weeds about 6-1/2 days later.

 

 

Lastly I want to go the direction that Ago has shown. It's going to take some time for me to figure it out.

Share this post


Link to post
Share on other sites

As MacrosBlack said the loop approach won't work. Another way to achieve the same thing would be a variable that is incremented by 1 every time checkForFarmGrowth method is ran. But the class is static so you can't create a instanced data object for every farm tile. I'm thinking you wouldn't want to anyway to minimize memory use. In this case using the database to store such a counter for each tile sounds better. The method's original design is basically just that, fetch a counter from data base, do stuff with that counter, and store a new value if changes need to be made.

 

 

Although, I still like the RNG algorithm approach. I'm thinking for each call to checkForFarmGrowth() method when tileAge is 6 there would be a 0.006 chance to go to weeds. I like the RNG way because its easy to code, uses little memory and doesn't require any DB or file-storage system. I arrived at 0.006 by 1 hr / 168 hr. a week has 168 hours. Using a 1 hour growth timer option, crops would be ripe in about 5 hours and would on average turn to weeds about 6-1/2 days later.

 

 

Lastly I want to go the direction that Ago has shown. It's going to take some time for me to figure it out.

 

What I am thinking, is something where... crops can be ripe in 20-40 minutes, and last 2-3 days at Ripe.  hard to get that type of stability with RNG.

 

The goal is, people have all the crops they need (fast players) and casual gamers don't have to worry about having to be on for 40-60 minutes in order to actually reap the crops they sow ;)

 

If something grows to Ripe in 20-40 minutes, and stays Ripe for several days... Lots of people are happy.

 

Also... couldn't you not increase the counter to 100... and have everything from 0-5 be the growing phase, and an IF statement being "ripe" ? If >100 weeds.

 

and have "100" a variable that a server admin could increase/decrease?

Edited by Jarosz

Share this post


Link to post
Share on other sites

The problem is that we don't know just how big that counter can get without screwing up all the other data in the tile data. All the data for the tile is stored in a single byte. This saves memory and speeds things up, but makes alterations like this difficult because the rest of the code expects certain pieces of information to be stored within certain bits of that byte.


Share this post


Link to post
Share on other sites

Unless you edit the code and compile it yourself, you won't retain previous modifications to the server files (unless all are in separate class files and you just replace them separately).  So if you want an easy way for undying crops (someone else compiles it for you), you would have to overwrite any existing server.jar modifications and replace it with the server.jar with the undying crops mod. 

 

I think calling the disband settlement sound file upon reaching tileAge 7 would be an acceptable alternative :)

 

 

Sia, the short answer is WU wasn't designed to be modded. Now, we [the players] have just jump right in and are wading through the problems of figuring out how to best go about modding. Specifically, in the case of no-weeds, the variables that need to be changed are hard coded constants.  

 

There are problems with sharing compiled classes. One of them is that a lot of mods will change the server's Terraforming.class. One modders compiled version of that class will replace another modders work. This problem exists for all class actualy but it's expecialy bad in Terraforming.class as that has many functions players will want to change.

The work to compile all possible combinations of different alteration is too much. Another is It makes it more complicated for me to share a compiled class that has say just the no weeds change. My Terraforming.class has other changes in it.

 

 

Sia, I don't expect you to know the answers to the following but I want to bring it up again because we really need to find a solution to the problem seen here.

I've mentioned a few time now an idea of a standardized modders server and client. These files would be altered versions that by default they run basic WU but with reflection tools modders can enable different function. In the case of no-weeds we might add something like the following to the modding jar files. I"m a total noob so I don't know if this is a good idea of not.

private static int maxCropAge = 7

private static float extendedDurationWeedsChance = 0.0F

.

.

.

if(tileAge < maxCropAge) {

// stuff

}

if(tileAge == maxCropAge && extendedDurationWeedsChance != 0.0F) {

// RNG code to change to weeds. RNG chance is low and on average will ripe crops

//to weeds have a much longer duration then it took to get to ripe.

}

note..Is it it right to use constants like that? It seems strange to me the constructor in that class isn't used at all.

 

Thank you both for your answers, very much appreciated. I understand, I suspected it might be something that I would have to implement in my own server/database. I will just have to learn then as I'm desperately willing to get this working for my personal creative server. :)

 

Joedobo, I like the idea of a standardized modders server and client. Anything that makes modding easier/more possible/offers more option is a good thing in my mind. There is unlimited potential in this, because Wurm is just one of those games that people play in so many different ways -- some are merchants, some play for the animals, some for the combat/hunting/pvp, some as crafters/builders/decorators, and some are even in it just for the grind -- and modding enables people do make the game "their own", best suited to their needs, depending on what they want to get out of the game. 

 

Also wanted to say thank you again for sharing this 'mod', I'm so excited about it!

Edited by Sia

Share this post


Link to post
Share on other sites

The tile data comes from the surface mesh. Each tile in there is 32bit.

* 16bit are for the tile height (actually the NW corner).

* 8bit is the tile type (dirt, field, grass, etc),

* 4 bit is the crop type (this gives at most 16 crop types, there are currently 14 crops defined),

* 3 bit is the crop age (stages 0 to 7, 7 is weeds)

* 1 bit is the farmed state

There is no space in the tile mesh to save this kind of information

But there also is the resource mesh. It stores the amount of resources on the tile. 16 bit is for the cave resoures, 16 bit is for surface resources (i.e. crop count).

So every iteration could add a random number to the harvest amount. Once it reaches a certain limit the tile could go to weed. To avoid insane 32k harvests there should also be an upper limit on the number when harvesting.

The information there is pretty packed too. But there's still the option of saving per tile data similar to Zones.protectedTiles

Edited by ago

Share this post


Link to post
Share on other sites

ago i would have a request to that mod, could you make it that you also increase the amount of crops you harvest? maybe a small option like regular crop harvest + additional [insert number],we can handle via the propertie file :)


Share this post


Link to post
Share on other sites

That's really deep in the Terraforming.harvest() method. That's probably the test how far one can go with bytecode manipulation.

Share this post


Link to post
Share on other sites

* 4 bit is the crop type (this gives at most 16 crop types, there are currently 14 crops defined),

 

Sad very sad! I wanted to add all plants to farmable crops. Am I correct I'd have to alter the surface mesh file to add more then 16?

 

Maybe instead I could add a new object, say raised farm beds, which wouldn't use surface mesh.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this