[Open Source] SkyBlock Minecraft Addon [New features #2]

in #utopian-io5 years ago (edited)


Hello steemians and minecraft players,

I added the last couple of days some new features to SKYBLOCK.SK, since people are really demanding and want new features FAST, I'm a little bit stressed out these days... =) But now, I want to show the new things I added to SKYBLOCK.SK, a fully customizeable SkyBlock experience for server operators to use without any Java knowledge. Licensed under the MIT license.

Repository

https://github.com/Abwasserrohr/SKYBLOCK.SK

Bug Fixes

People really want new stuff, that's why I didn't fix all bugs and rather added new enhancements to the game and fix minor bugs later. There is only one bug i had to fix, since it really bothered me that it doesn't work:


  • Island delete doesn't delete islands
    I thought it would be nice to delete islands on load in a threaded process. Because it turns out that removing blocks in a thread isn't working, this has to be in the main thread of the game to work.

  • Solution
    That's why islands are now no longer removed within a thread. This is a fast fix, only one line had to be changed, but sometimes it takes longer to find why it's not working than only removing one line.. =D I also added some comments, like I always do if I come across something that could need some comments.

  • Direct Link
    https://github.com/Abwasserrohr/SKYBLOCK.SK/pull/32/commits/2bc4a30763fb69a68c8429eedf7ca2bb62b492f0


New Features

Now, there are some new additions to the game, which have been added by me:


  1. Added elevators
  2. Added default island
  3. Added automatic island file copy to world folder
  4. Added ore generator leveling system

Elevators

Players can build their islands from the bottom to the top, this gives the players around 256 blocks of height to build on, it can be frustrating to get from the bottom to the top. That's why an elevator is now giving the players the opportunity to place two signs which are on the same x and z axis and then being transported either up or down very safe and fast. Players only need two signs for this to work, then they place the sign on a wall and put in the following content:
  1. Line: [Lift]
  2. Line: Up or Down
  3. Line: Custom text
  4. Line: Custom text

The custom text can help players to know where they are going. Once the sign is placed, the skript is going to format the sign to make it active. Like you can see on the pictures.

The sign formatting is done by the "on sign change" trigger, which detects if a sign is changed (placed) by a player:

on sign change:
    if line 1 of event-block is "[Lift]":
        if line 2 of event-block is "Up" or "Down":
            set line 1 of event-block to {@sign_lift}
            if line 2 of event-block is "Down":
                set line 2 of event-block to {@sign_down}
            if line 2 of event-block is "Up":
                set line 2 of event-block to {@sign_up}

The variable-like looking {@text} options can be set for a skript like this and allow changes faster on the skript:

options:
    sign_down: "↓ DOWN ↓"
    sign_up: "↑ UP ↑"
    sign_lift: "&l[LIFT]"

Once it is formatted and a player clicks on it, a trigger detecting the click on [Lift] signs and then looks if the sign says either Up or Down to look for other [Lift] signs.

As soon as it knows if it should go either up or down, it goes trough all blocks above the [Lift] sign the player clicked on or below and as soon as it hit a sign with [Lift] on the first line, it is going to change the y-coordinate of the player's location to the difference between the two signs and then teleports the player to the new location.

This is how the process works in the skript:

on rightclick on sign:
    if line 1 of event-block is {@sign_lift}:
        set {_loc::1} to location of event-block
        set {_loc::2} to {_loc::1}
        if line 2 of event-block is {@sign_down}:
            set y-coordinate of {_loc::1} to 0
            remove 1 from y-coordinate of {_loc::2}
        else if line 2 of event-block is {@sign_up}:
            set y-coordinate of {_loc::1} to 256
            add 1 to y-coordinate of {_loc::2}
        else:
            stop
        loop blocks within {_loc::1} to {_loc::2}:
            if loop-block is sign:
                if line 1 of loop-block is {@sign_lift}:
                    set {_ploc} to location of player
                    if line 2 of event-block is {@sign_down}:
                        set {_diff} to difference between y-coordinate of event-block and y-coordinate of loop-block
                        remove {_diff} from y-coordinate of {_ploc}
                    else if line 2 of event-block is {@sign_up}:
                        set {_diff} to difference between y-coordinate of event-block and y-coordinate of loop-block
                        add {_diff} to y-coordinate of {_ploc}
                    if the block below {_ploc} is air:
                        add 0.5 to y-coordinate of {_ploc}
                    if the block below {_ploc} is air:
                        stop
                    teleport player to {_ploc}

If the player is using half slabs, elevator.sk also is making sure that the player is going to land on a block. If it can't make sure that the player lands on a block, the elevator prevents the player from using it.

elevator.sk is created to also work without SKYBLOCK.SK and only adds elevators. This is also helpful for other game types like survival, factions or freebuild.

Direct Link
https://github.com/Abwasserrohr/SKYBLOCK.SK/pull/32/commits/47bc1c9502db5c288c58f857867e1dbf600e043e


Default island

To make it as easy as possible for new server operators to get SKYBLOCK.SK to work, there is now a default island which is already predefined in the configuration.

Now, server operators can simply take the zip from GitHub, unzip it and paste the SkyBlock folder into the "plugins/Skript/scripts" folder and then start the game, only a lobby island has to be built and then the server is ready to start.

Additional tutorials, how prepare everything should be added in the future. Also, this could be automated on first start if the server operator wants this.

I also changed the default size of all structure files to 32x32x32, which is the maximum size. If someone wants to add new structures, they should use the same format. Which is later included in the documentation how to do that.

Direct Link
https://github.com/Abwasserrohr/SKYBLOCK.SK/pull/34


Added automatic island file copy to world folder

Now, we have a default island in our "plugins/Skript/scripts/SkyBlock/islands" folder. To prevent further complexity for server operators, the skript is copying these files automatically to the right place, the "worldname/generated/minecraft/structures" folder, in which all structure files are stored and loaded trough the game by default.

To make this possible, I used skript-mirror to import the following Java classes:

import:
    java.io.File
    java.io.FileInputStream
    java.io.FileOutputStream

Then, I created a function which can be used to import the files to the right place, this is started once the config.sk file is loaded:

function loadislandstoworld():
    set {_files::*} to ...new File("plugins/Skript/scripts/SkyBlock/islands").listFiles()
    loop {_files::*}:
        set {_check} to loop-value.toString().endsWith(".nbt")
        if {_check} is true:
            send "[SkyBlock] > Try to import %{_fname}% into your world..." to console
            set {_fname} to loop-value.getName()
            set {_checkfile} to new File("%{SB::config::world}%/generated/minecraft/structures/%{_fname}%")
            if {_checkfile}.isFile() is true:
                send "[SkyBlock] > %{_fname}% is already set." to console
            else:
                set {_source} to loop-value
                set {_dest} to {_checkfile}
                set {_sourceChannel} to null
                set {_destChannel} to null
                set {_sourceChannel} to new FileInputStream({_source}).getChannel()
                set {_destChannel} to new FileOutputStream({_dest}).getChannel()
                {_destChannel}.transferFrom({_sourceChannel}, 0, {_sourceChannel}.size())
                {_sourceChannel}.close()
                {_destChannel}.close()
                send "[SkyBlock] > Successfully imported %{_fname}%!" to console

This function takes a list of files from our "plugins/Skript/scripts/SkyBlock/islands" folder and then loop through all files, if a file in that folder ends with ".nbt", which is the file format for structure files, we are going look if there is already a file with that name, if there is one, it won't overwrite it, since it could be something else.

If there is nothing else, it is opting a new FileInputStream and FileOutputStream and then transfers the file from our source to the new configured destination.

This helps new server operators, since they don't have to move the structure files around on the server and makes installation time shorter.

Direct Link
https://github.com/Abwasserrohr/SKYBLOCK.SK/pull/32/commits/1f2d0225078aa5e3b3eb143a2478cd6fab19eb95

Pictures


Ore generator leveling system

The ore generator leveling is a new feature to SKYBLOCK.SK, which can also be disabled, if a server operator doesn't want this. This allows players to level up their ore generator by using it. It counts how many times the generator of a player has produced a new block and then level it up.

How fast it is leveling, how much it is changing the ore generation chance and also how much harder it should be to get to the next level after another can be defined in the configuration of SKYBLOCK.SK.

This opens the opportunity for players to mine all day long on the ore generator and get better spawning rates of ores out of the ore generator, this makes the whole SkyBlock experience richer and more enjoyable.

The add-on, which has been changed is the "oregenerator.sk", the first change i did, was to shorten the event "on flow" and do the most within a function:

on flow:
    if event-block is lava:
        $ thread
        loop blocks in radius 1 of event-block:
            if y-coordinate of event-block is y-coordinate of loop-block:
                if loop-block is cobblestone:
                    oregeneratorplace(location of loop-block)

This way, the trigger "on flow" looks cleaner than before and it is easier to read. The "oregeneratorplace", which is being executed here is a new 1 out of 3 new functions included in the new oregenerator.sk add-on.

To make the leveling as compact as possible, leveling happens directly in the "oregeneratorplace" function,
which is either working like before, with ore generator leveling set to false or like this:

  1. Loop trough all players around the ore generator until it finds a player
  2. Add 1 to the players ore generator statistics, this changes the level of the ore generator
  3. Set players ore generator level to 0 if it is not set
  4. Set the {_defaultlvl} variable to the blocks the ore generator statistics of the player (integer, all blocks produced by the ore generator already)
  5. Set the {_level} variable to 0
  6. Set the {_defaultlvl} to ({_defaultlvl} / {SB::config::oregennewlevel})
    This is the threshold for the first level, which is defined in the configuration. Default: 1000.
    7.1. How this works?
    7.2. Since {_defaultlvl} is an integer of all blocks the player has generated with the ore generator and we're needing to know on which level he is and we're knowing how many blocks he needs for the first level, we can easily subtract the blocks, he has been producing trough the blocks the player needs for his first level.
    7.3. Then we have either a number of below 1, exactly 1 or above 1
    7.4. If the number is equal or higher than 1, the player levels up
    7.5. On level up, the next level threshold is multiplied by a configurable integer in the configuration
    7.6. This process is repeated until {_defaultlvl} is lower than 1.
  7. Now we loop trough the chances and blocks which are configured in the configuration file.
  8. Then, we calculate the chance by using the level and the level chance multiply out of the configuration and also calculating the maximum multiplying bonus.
  9. Once that's done, it is checked that the chance is not higher than the maximum multiply bonus or higher than 100.
  10. Then, the chance is being applied, if it happened, the player gets the ore.
  11. That's all it does, i hope this helps to understand what's going on, I also added comments in the file, of course! =)
function oregeneratorplace(l:location):
    if {SB::config::oregeneratorleveling} is true:
        loop players in radius 20 of {_l}:
            set {_uuid} to uuid of loop-player
            set {_player} to loop-player
            stop loop
        add 1 to {SB::ogplayerblocks::%{_uuid}%}
        if {SB::ogplayerlevel::%{_uuid}%} is not set:
            set {SB::ogplayerlevel::%{_uuid}%} to 0
        set {_defaultlvl} to {SB::ogplayerblocks::%{_uuid}%} 
        set {_level} to 0
        set {_defaultlvl} to ({_defaultlvl} / {SB::config::oregennewlevel})
        set {_blocksneeded} to {SB::config::oregennewlevel}
        loop {_defaultlvl} times:
            if {_defaultlvl} >= 1:
                set {_blocksneeded} to ({_blocksneeded} * {SB::config::oregenlevelmultiplyer})
                add 1 to {_level}
                set {_defaultlvl} to ({_defaultlvl} / {SB::config::oregenlevelmultiplyer})
            else:
                stop loop
        loop {SB::oregenc::*}:
            set {_chance} to loop-value+((loop-value/100)*({SB::config::oregenlevelbonus}*{_level}))
            set {_maxchance} to loop-value+((loop-value/100)*{SB::config::oregenmaxlevelbonus})
            if {_chance} is bigger than {_maxchance}:
                set {_chance} to {_maxchance}
            if {_chance} is bigger than 100:
                set {_chance} to 100
            chance of {_chance}%:
                #
                # > If the player has been lucky, this is setting the block to the new "lucky" block and then
                # > stops the function.
                set block at {_l} to {SB::oregen::%loop-index%}
                stop
    else:
        loop {SB::oregenc::*}:
            chance of loop-value%:
                set block at {_l} to {SB::oregen::%loop-index%}
                stop

This is the new process of leveling and of the ore generator itself, but now we have to output some stuff to the player, since they might want to know on which level they are and how their ore generator chances are, this is done by two functions:



function generatorinfo(p:player):
    set {_uuid} to uuid of {_p}
    set {_player} to {_p}
    if {SB::config::oregeneratorleveling} is false:
        send "%{SB::lang::prefix::%{SK::lang::%{_uuid}%}%}% %{SB::lang::og::disabled::%{SK::lang::%{_uuid}%}%}%" to {_player}
        stop
    if {SB::ogplayerlevel::%{_uuid}%} is not set:
        set {SB::ogplayerlevel::%{_uuid}%} to 0
    set {_defaultlvl} to {SB::ogplayerblocks::%{_uuid}%}
    set {_level} to 0
    set {_defaultlvl} to ({_defaultlvl} / {SB::config::oregennewlevel})
    set {_blocksneeded} to {SB::config::oregennewlevel}
    loop {_defaultlvl} times:
        if {_defaultlvl} >= 1:
            set {_blocksneeded} to ({_blocksneeded} * {SB::config::oregenlevelmultiplyer})
            add 1 to {_level}
            set {_defaultlvl} to ({_defaultlvl} / {SB::config::oregenlevelmultiplyer})
        else:
            stop loop
    set {_prefix} to {SB::lang::prefix::%{SK::lang::%{_uuid}%}%}
    send "%{SB::config::spacer}%" to {_player}
    send "%{_prefix}% %{SB::lang::og::name::%{SK::lang::%{_uuid}%}%}%" to {_player}
    send "%{_prefix}% %{SB::lang::og::currentlvl::%{SK::lang::%{_uuid}%}%}% %{_level}%" to {_player}
    set {_progress} to "%{SB::config::color::secondary::2}%||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||&r"
    set {_progressloop} to {_defaultlvl} * 100
    loop {_progressloop} times:
        replace all "%{SB::config::color::secondary::2}%|" with "%{SB::config::color::primary::1}%|%{SB::config::color::secondary::2}%" in {_progress}
    send "%{_prefix}% %{_progress}% (%{_progressloop}%%%)" to {_player}
    set {_pr} to {SB::lang::og::progress::%{SK::lang::%{_uuid}%}%}
    replace all "<c>" with "%{SB::ogplayerblocks::%{_uuid}%}%" in {_pr}
    replace all "<n>" with "%{_blocksneeded}%" in {_pr}
    send "%{_prefix}% %{_pr}%" to {_player}
send "%{SB::config::spacer}%" to {_player}

This works similar to the "oregeneratorplace" function, but it only prints out the information to the defined player instead of doing anything else. To make this complete, this is the function which displays the ore spawning chances of the ore generator for the specified player to the player.

The function calculates the chance like the "oregeneratorplace" function by adding the percentage to the existing statistics from the players ore generator level and then giving the player the detailed information about all chances he has:



function orechancesinfo(p:player):
    set {_uuid} to uuid of {_p}
    set {_player} to {_p}
    send "%{SB::config::spacer}%" to {_player}
    set {_prefix} to {SB::lang::prefix::%{SK::lang::%{_uuid}%}%}
    send "%{_prefix}% %{SB::lang::og::chancesforyou::%{SK::lang::%{_uuid}%}%}%" to {_player}
    loop {SB::oregenc::*}:
        if {SB::config::oregeneratorleveling} is false:
            send "%{_prefix}% %loop-value%%%: %{SB::oregen::%loop-index%}%" to {_player}
        else:
            set {_chance} to loop-value+((loop-value/100)*({SB::config::oregenlevelbonus}*{SB::ogplayerlevel::%{_uuid}%}))
            set {_maxchance} to loop-value+((loop-value/100)*{SB::config::oregenmaxlevelbonus})
            if {_chance} is bigger than {_maxchance}:
                set {_chance} to {_maxchance}
            if {_chance} is bigger than 100:
                set {_chance} to 100
            send "%{_prefix}% %{_chance}%%%: %{SB::oregen::%loop-index%}%" to {_player}
    send "%{SB::config::spacer}%" to {_player}

The functions are also commented on GitHub, i'll suggest to look there if you want to know exactly what's going on here.. =)

This feature is directly included in SKYBLOCK.SK, since it needs translation and configuration, there are also changes in other files, the changes are all in the pull request below.

  • config.sk
  • SkyBlock/SKYBLOCK.SK/Commands.sk
  • SkyBlock/lang/de.sk

Direct Link
https://github.com/Abwasserrohr/SKYBLOCK.SK/blob/master/SkyBlock/addons/oregenerator.sk

Pull request
https://github.com/Abwasserrohr/SKYBLOCK.SK/pull/35


Now, I really hope the players appreciate the new elevator and the new ore generator leveling system. This took time, but I think it is a very big enhancement for the game. I'm looking forward to add more features and also balancing things out, since the new generator might be too good and needs some changes in the configuration.


Pull requests

https://github.com/Abwasserrohr/SKYBLOCK.SK/pull/32
https://github.com/Abwasserrohr/SKYBLOCK.SK/pull/34
https://github.com/Abwasserrohr/SKYBLOCK.SK/pull/35

GitHub Account

https://github.com/Abwasserrohr

How to contribute

If you're interested in contributing to this project, I'll look forward to meet you in Discord, just hop on our server and ask Abwasserrohr, the sewage pipe! =) No matter if you're a coder or new to coding, Skript is exactly made to make it easy to read, learn and create new code. Of course, there are hard parts and it might look complicated, since skript can also use java classes, thanks to skript-mirror. But starting is easy and a hello world is done in 15 minutes, including setting up the boilerplate, server and everything you need.

Discord: https://discord.gg/FRuK5BC

I also help people with skript and Java in general, if help is needed, just ask me, i always try my best to help new people. :3
Also, it is possible to create pull requests or fork the project and enhance the project further, if you're already into skript. =)


Thanks for reading this contribution post, I added more pictures this time, since there are more visual things, which have been done this time. =) Hope you guys liked it. As always, I really appreciate comments and feedback.

Keep on steeming,

@immanuel94

Sort:  
  • Great post, lots of content, code and images.
  • Congrats on the comments in the code. I think this is the most I've ever seen.
  • The quality of your posts is improving quickly. They will soon become very instructive, I can feel it.

Your contribution has been evaluated according to Utopian policies and guidelines, as well as a predefined set of questions pertaining to the category.

To view those questions and the relevant answers related to your post, click here.


Need help? Write a ticket on https://support.utopian.io/.
Chat with us on Discord.
[utopian-moderator]

Hey @helo,

thanks for reviewing my contribution. =)

I might have used too much comments this time.
It's always fun for me to create posts like this, I'll try to improve it further in the future. :3

I wish you a nice sunday

@immanuel94

Thank you for your review, @helo! Keep up the good work!

Hi @immanuel94!

Your post was upvoted by @steem-ua, new Steem dApp, using UserAuthority for algorithmic post curation!
Your UA account score is currently 2.250 which ranks you at #20337 across all Steem accounts.
Your rank has not changed in the last three days.

In our last Algorithmic Curation Round, consisting of 216 contributions, your post is ranked at #164.

Evaluation of your UA score:
  • Only a few people are following you, try to convince more people with good work.
  • The readers like your work!
  • Try to work on user engagement: the more people that interact with you via the comments, the higher your UA score!

Feel free to join our @steem-ua Discord server

Hey, @immanuel94!

Thanks for contributing on Utopian.
We’re already looking forward to your next contribution!

Get higher incentives and support Utopian.io!
Simply set @utopian.pay as a 5% (or higher) payout beneficiary on your contribution post (via SteemPlus or Steeditor).

Want to chat? Join us on Discord https://discord.gg/h52nFrV.

Vote for Utopian Witness!

Coin Marketplace

STEEM 0.29
TRX 0.12
JST 0.033
BTC 62934.09
ETH 3118.65
USDT 1.00
SBD 3.85