Modding:WorldGen API: Difference between revisions

From Vintage Story Wiki
Line 233: Line 233:


== Placing blocks during world gen ==
== Placing blocks during world gen ==
The server does not generate chunks on the main game thread because the game's frame rate would drop significantly and it would really be disruptive to game play. The server spawns a separate thread for this and there is a special IBlockAccessor that is used in that thread that we need to get a reference to in order to place our chest. First lets add two variables at the top of our class of type IBlockAccessor. One to hold our game thread IBlockAccessor and one to hold the one used by the server world gen thread.
The server does not generate chunks on the main game thread because the game's frame rate would drop significantly and it would really be disruptive to game play. The server spawns a separate thread for this and there is a special '''IBlockAccessor''' that is used in that thread that we need to get a reference to in order to place our chest. First lets add two variables at the top of our class of type '''IBlockAccessor'''. One to hold our game thread '''IBlockAccessor''' and one to hold the one used by the server world gen thread.
<syntaxhighlight lang="c#">
<syntaxhighlight lang="c#">
private IBlockAccessor chunkGenBlockAccessor;
private IBlockAccessor chunkGenBlockAccessor;
Line 239: Line 239:
</syntaxhighlight>
</syntaxhighlight>


Let's initialize worldBlockAccessor at the top of StartServerSide. This is the IBlockAccessor we used in our /treasure command. Later we will refactor that code to use this variable.
Let's initialize '''worldBlockAccessor''' at the top of '''StartServerSide'''. This is the '''IBlockAccessor''' we used in our '''/treasure''' command. Later we will refactor that code to use this variable.
<syntaxhighlight lang="c#">
<syntaxhighlight lang="c#">
this.worldBlockAccessor = api.World.BlockAccessor;
this.worldBlockAccessor = api.World.BlockAccessor;
</syntaxhighlight>
</syntaxhighlight>
Next we will register a call back delegate to be passed the IBlockAccessor we need. Place this in OnServerStart.
Next we will register a call back delegate to be passed the '''IBlockAccessor''' we need. Place this in '''StartServerSide'''.
<syntaxhighlight lang="c#">
<syntaxhighlight lang="c#">
this.api.Event.GetWorldgenBlockAccessor(OnWorldGenBlockAccessor);
this.api.Event.GetWorldgenBlockAccessor(OnWorldGenBlockAccessor);
Line 254: Line 254:
}
}
</syntaxhighlight>
</syntaxhighlight>
Let's do a quick refactoring before we move on. Remember our PlaceTreasureChestInFrontOfPlayer method? The code in that to place the chest is going to be reused by our world gen code but we won't have a player in that case and we will also need to use a different IBlockAccessor to place our block. So let's refactor that to use a new method we call PlaceTreasureChest. So replace PlaceTreasureChestInFrontOfPlayer with the following.
Let's do a quick refactoring before we move on. Remember our '''PlaceTreasureChestInFrontOfPlayer''' method? The code in that to place the chest is going to be reused by our world gen code but we won't have a player in that case and we will also need to use a different '''IBlockAccessor''' to place our block. So let's refactor that to use a new method we call '''PlaceTreasureChest'''. So replace '''PlaceTreasureChestInFrontOfPlayer''' with the following.
<syntaxhighlight lang="c#">
<syntaxhighlight lang="c#">
private void PlaceTreasureChestInFrontOfPlayer(IServerPlayer player, int groupId, CmdArgs args)
private void PlaceTreasureChestInFrontOfPlayer(IServerPlayer player, int groupId, CmdArgs args)
Line 280: Line 280:
}
}
</syntaxhighlight>
</syntaxhighlight>
So what we did is make a PlaceTreasureChest that takes an IBlockAccessor and a BlockPos for placing the chest. The null check on chestEntity is probably not necessary however while developing this I found I was misusing the API by using the wrong IBlockAccessor so the null check helps detect this scenario and provides a more meaningful message than just a NullReferenceException so I suggest leaving this in. Also notice that we are printing a message to the console when a chest is placed. This is also optional however it's helpful for finding chests in the world when testing. Our PlaceTreasureChestInFrontOfPlayer method now calls our new method passing it the appropriate IBlockAccessor and the BlockPos 2 blocks in front of the player. Now that this refactoring has been done, we are ready to find a suitable spot to place our chests.
So what we did is make a '''PlaceTreasureChest''' that takes an '''IBlockAccessor''' and a '''BlockPos''' for placing the chest. The null check on '''chestEntity''' is probably not necessary however while developing this I found I was misusing the API by using the wrong IBlockAccessor so the null check helps detect this scenario and provides a more meaningful message than just a NullReferenceException so I suggest leaving this in. Also notice that we are printing a message to the console when a chest is placed. This is also optional however it's helpful for finding chests in the world when testing. Our '''PlaceTreasureChestInFrontOfPlayer''' method now calls our new method passing it the appropriate '''IBlockAccessor''' and the '''BlockPos''' 2 blocks in front of the player. Now that this refactoring has been done, we are ready to find a suitable spot to place our chests.


== Finding where to place the chest ==
== Finding where to place the chest ==