Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
joserobjr committed Aug 19, 2020
0 parents commit c4b9c11
Show file tree
Hide file tree
Showing 8 changed files with 306 additions and 0 deletions.
18 changes: 18 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Created by .ignore support plugin (hsz.mobi)
### Maven template
target/
pom.xml.tag
pom.xml.releaseBackup
pom.xml.versionsBackup
pom.xml.next
release.properties
dependency-reduced-pom.xml
buildNumber.properties
.mvn/timing.properties
# https://github.com/takari/maven-wrapper#usage-without-binary-jar
.mvn/wrapper/maven-wrapper.jar

.idea
*.iml
.project
/run
24 changes: 24 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
This is free and unencumbered software released into the public domain.

Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.

In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

For more information, please refer to <https://unlicense.org>
34 changes: 34 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Example Plugin for PowerNukkit
This is an example plugin which can also be used as template to start your own plugin.

As an example I created a plugin named clone-me, it creates a clone of yourself when you run `/clone`
and gives you a flower if you hit the clone and then despawn the clone. It also send some fancy messages.

These is enough to serve as an example on how to:
- Begin a new plugin
- Create event listeners and handlers
- Create custom commands
- Format text
- Spawn NPCs
- Despawn NPCs
- Detect attacks
- Make entities invulnerable
- Create and fill a `plugin.yml` file
- Debug your plugin properly

## Cloning and importing
1. Just do a normal `git clone https://github.com/PowerNukkit/ExamplePlugin.git` (or the URL of your own git repository)
2. Import the `pom.xml` file with your IDE, it should do the rest by itself

## Debugging
1. Create a zip file containing only your `plugin.yml` file
2. Rename the zip file to change the extension to jar
3. Create an empty folder anywhere, that will be your server folder.
<small>_Note: You don't need to place the PowerNukkit jar in the folder, your IDE will load it from the maven classpath._</small>
4. Create a folder named `plugins` inside your server folder
<small>_Note: It is needed to bootstrap your plugin, your IDE will load your plugin classes from the classpath automatically,
so it needs to have only the `plugin.yml` file._</small>
5. Move the jar file that contains only the `plugin.yml` to the `plugins` folder
6. Create a new Application run configuration setting the working directory to the server folder and the main class to: `cn.nukkit.Nukkit`
![](https://i.imgur.com/NUrrZab.png)
7. Now you can run in debug mode. If you change the `plugin.yml` you will need to update the jar file that you've made.
23 changes: 23 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<name>ExamplePlugin</name>
<artifactId>example-plugin</artifactId>
<groupId>org.powernukkit.plugins</groupId>
<version>0.1.0-SNAPSHOT</version>
<packaging>jar</packaging>

<dependencies>
<dependency>
<groupId>org.powernukkit</groupId>
<artifactId>powernukkit</artifactId>
<version>1.3.1.4-PN</version>
</dependency>
</dependencies>

<properties>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.source>1.8</maven.compiler.source>
</properties>
</project>
32 changes: 32 additions & 0 deletions src/main/java/org/powernukkit/plugins/example/CloneCommand.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package org.powernukkit.plugins.example;

import cn.nukkit.Player;
import cn.nukkit.command.Command;
import cn.nukkit.command.CommandExecutor;
import cn.nukkit.command.CommandSender;
import cn.nukkit.entity.EntityHuman;
import cn.nukkit.nbt.tag.CompoundTag;
import cn.nukkit.utils.TextFormat;

public class CloneCommand implements CommandExecutor {
@Override
public boolean onCommand(CommandSender commandSender, Command command, String s, String[] strings) {
if (!(commandSender instanceof Player)) {
commandSender.sendMessage(TextFormat.DARK_RED+""+TextFormat.BOLD + "Error!"+TextFormat.RESET+TextFormat.RED+" Only players can execute this command!");
return false;
}
Player player = (Player) commandSender;
player.saveNBT();
EntityHuman human = new EntityHuman(player.getChunk(), new CompoundTag()
.put("Pos", player.namedTag.get("Pos").copy())
.put("Rotation", player.namedTag.get("Rotation").copy())
.put("Motion", player.namedTag.get("Motion").copy())
.put("Skin", player.namedTag.get("Skin").copy())
.putBoolean("IsCloned", true)
);
human.setSkin(player.getSkin());
human.spawnToAll();
player.sendMessage(TextFormat.DARK_GREEN+""+TextFormat.BOLD+"Success!"+TextFormat.RESET+TextFormat.GREEN+" You have been cloned!");
return true;
}
}
45 changes: 45 additions & 0 deletions src/main/java/org/powernukkit/plugins/example/CloneListener.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package org.powernukkit.plugins.example;

import cn.nukkit.Player;
import cn.nukkit.block.BlockID;
import cn.nukkit.entity.Entity;
import cn.nukkit.entity.EntityHuman;
import cn.nukkit.event.EventHandler;
import cn.nukkit.event.Listener;
import cn.nukkit.event.entity.EntityDamageByEntityEvent;
import cn.nukkit.item.Item;
import cn.nukkit.utils.TextFormat;

public class CloneListener implements Listener {
@EventHandler
public void onCloneDamage(EntityDamageByEntityEvent event) {
Entity entity = event.getEntity();

// Affect only the clones
if (!(entity instanceof EntityHuman)
|| !entity.namedTag.getBoolean("IsCloned")) {
return;
}

// Makes the clones invulnerable to non-player damage
if (!(event.getDamager() instanceof Player)) {
event.setCancelled();
return;
}

// If the clone is hit by a player, despawn it
Player player = (Player) event.getDamager();
player.sendMessage(TextFormat.GOLD+""+TextFormat.BOLD+"WOW!"+TextFormat.RESET+TextFormat.YELLOW+" You found a clone!");
entity.close();

// And give the player a present
Item flowerItem = Item.getBlock(BlockID.RED_FLOWER);
flowerItem.setCustomName(TextFormat.RESET+""+TextFormat.RED+"Congratulations!");
flowerItem.setLore(TextFormat.RESET+""+TextFormat.LIGHT_PURPLE+"This is a present for your finding!");

// The will guarantee that the player receive the present by dropping it on the floor if the inventory is full
for (Item drop: player.getInventory().addItem(flowerItem)) {
player.getLevel().dropItem(player, drop);
}
}
}
52 changes: 52 additions & 0 deletions src/main/java/org/powernukkit/plugins/example/CloneMePlugin.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package org.powernukkit.plugins.example;

import cn.nukkit.command.Command;
import cn.nukkit.command.CommandSender;
import cn.nukkit.command.PluginCommand;
import cn.nukkit.plugin.PluginBase;

public class CloneMePlugin extends PluginBase {
@Override
public void onEnable() {
getLogger().info("Hello world! :D");
if (System.getProperty("os.name").startsWith("Windows")) {
getLogger().warning("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
getLogger().warning("!!! ATTENTION WINDOWS USER !!!");
getLogger().warning("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
getLogger().warning("To connect to the server in localhost you must allow the game to access localhost:");
getLogger().warning("1. Open PowerShell as admin");
getLogger().warning("2. Run this command: CheckNetIsolation LoopbackExempt -a -n=\"Microsoft.MinecraftUWP_8wekyb3d8bbwe\"");
getLogger().warning("3. Restart your computer (if needed, try to restart your game first)");
getLogger().warning("This issue occurs due to loopback restrictions on Windows 10 UWP apps");
}

getLogger().info("TIP: Make sure your break points are set to pause ONLY THE THREAD and NOT ALL THREADS!");
getLogger().info("https://imgur.com/ygwen76");
getLogger().info("If you do this, you won't get disconnected when you hit a break point");

getLogger().info("TIP: If you are using IntelliJ, use Ctrl+F9 (Build Project) to apply non-structural java changes without restart");

// TODO: Make it easier
// This make the command be executed in a separated class, you need to choose if you want
// it being executed there or in the onCommand bellow, you can't use both
// Simple commands are fine in onCommand but complex command might be more organized
// in their own classes. Also make sure you register this command in plugin.yml
((PluginCommand<?>) getCommand("cloneme")).setExecutor(new CloneCommand());

// You must register your listeners to capture events
// You can make this class implement the Listener itself and invoke registerEvents(this, this)
// But again, if the listener gets too complicated it might be better to group them in different classes
getServer().getPluginManager().registerEvents(new CloneListener(), this);
}

@Override
public void onDisable() {
getLogger().info("Goodbye world :(");
}

@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
// You can also override this command instead of setting an executor in onEnable if you prefer
return false;
}
}
78 changes: 78 additions & 0 deletions src/main/resources/plugin.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# Required
# The final name of your plugin, other plugins may use this name to declare dependency on your plugin
name: CloneMe

# Required
# The name of your class file that overrides PluginBase
main: org.powernukkit.plugins.example.CloneMePlugin

# Required
# The version of your plugin, it's recommended to follow the https://semver.org/ standard
version: "1.0.0"

# Required
# The minimum Cloudburst Nukkit API version, it's not the PowerNukkit version!
# Setting an outdated version usually don't cause issues so it's not a thing to worry too much
api: ["1.0.0"]

# Optional
# At which time your plugin will load.
# Valid options are: POSTWORLD, STARTUP
# Default value is POSTWORLD
load: POSTWORLD

# Optional
# Your name or your organization name or how people identify you
author: Nukkit Project

# Optional
# Explain in few words what this plugin does
description: Example plugin showing the API

# Optional
# A link where the admins can find more info about your plugin
website: https://github.com/Nukkit/ExamplePlugin

# Optional
# Every sub-item must be a block, the key is the command name, you can create as many commands as you want
# Make sure to keep the exact same alignment, it is important
commands:
# The key is how the command will be used, like /cloneme . Avoid uppercase, the client game don't like it so much and may crash.
cloneme:
# Optional
# This information will be displayed in /help
description: Example command

# Optional
# This information will be displayed in /help and when your command executor returns false
usage: "/example"

# Optional
# The permission required to use your command. It's a good practice to always define one even if the command can be used by everybody
# More information below
permission: cloneme.cmd.use

# Optional
# Although you don't need to register your permissions here for them to work, it's good to allow the server owners to see all them quicker
# This section also allows to customize their behavior and provide more information about them
# You can also create group of permission
# Also, every sub-item must be a block just like the commands block above
permissions:
# The key must be the same value you use to define the permission
# It's a good practice to prefix it with your plugin name and create segmentation and then group them to make the permission management easier
cloneme.cmd.use:
# Optional
# This can be used by permission management plugins to show details about the permission key
description: "Allows the user to run the example command"

# Optional
# If a player don't have an allow-deny definition for this key, this default value will be used
# Valid options:
# - true: the permission is granted by default to everybody
# - false: the permission is revoked by default to everybody, including admins and OP
# - op: the permission is revoked by default to everybody, but is granted to OP players
# - notop: the permission is granted by default to everybody, but is revoked to OP players
# Default value is false
default: true

# TODO Add all possible configuration here

0 comments on commit c4b9c11

Please sign in to comment.