Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,20 @@ player.setCamera("minecraft:free", {0, 100, 0}, {30, 90, 0}, 2.0f, falcon::Camer
player.fadeCamera(0.5f, 1.0f, 0.5f, 0x000000);
```

### Administration

`falcon::Server` reaches the ban lists, the allow list, the server list entry, the tick rate and the other plugins:

```cpp
falcon::Server::ban("Griefer", "Breaking the spawn");
falcon::Server::allowListAdd("Friend");
falcon::Server::setMotd("Falcon - event tonight");
if (falcon::Server::tps() < 15.0)
falcon::Server::broadcast("The server is under load");
for (const std::string &name: falcon::Server::plugins())
logger().info(name + " " + falcon::Server::pluginVersion(name).value_or("?"));
```

### C# plugins

The `dotnet` runtime is deprecated. Write new plugins for Wasm, native C++ or Java.
Expand Down
155 changes: 155 additions & 0 deletions java/src/main/java/falcon/api/Server.java
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,161 @@ public boolean unloadWorld(String name) {
}
}

/**
* Bans a name, like /ban, and kicks the player when online; the reason is shown to them.
*/
public boolean ban(String name, String reason) {
try (Arena arena = Arena.ofConfined()) {
return api().serverBan(Interop.text(arena, name), Interop.text(arena, reason),
api().pluginName(mContext.handle())) != 0;
}
}

public boolean pardon(String name) {
try (Arena arena = Arena.ofConfined()) {
return api().serverPardon(Interop.text(arena, name)) != 0;
}
}

public boolean isBanned(String name) {
try (Arena arena = Arena.ofConfined()) {
return api().serverIsBanned(Interop.text(arena, name)) != 0;
}
}

public List<String> bannedNames() {
int count = api().serverBanCount();
List<String> names = new ArrayList<>(Math.max(count, 0));
for (int index = 0; index < count; index++) {
names.add(Interop.string(api().serverBannedName(index)));
}
return names;
}

/**
* Bans an address, like /ban-ip, and kicks every player connected from it.
*/
public boolean banIp(String address, String reason) {
try (Arena arena = Arena.ofConfined()) {
return api().serverBanIp(Interop.text(arena, address), Interop.text(arena, reason),
api().pluginName(mContext.handle())) != 0;
}
}

public boolean pardonIp(String address) {
try (Arena arena = Arena.ofConfined()) {
return api().serverPardonIp(Interop.text(arena, address)) != 0;
}
}

public boolean isIpBanned(String address) {
try (Arena arena = Arena.ofConfined()) {
return api().serverIsIpBanned(Interop.text(arena, address)) != 0;
}
}

public List<String> bannedIps() {
int count = api().serverIpBanCount();
List<String> addresses = new ArrayList<>(Math.max(count, 0));
for (int index = 0; index < count; index++) {
addresses.add(Interop.string(api().serverBannedIp(index)));
}
return addresses;
}

public boolean allowListAdd(String name) {
try (Arena arena = Arena.ofConfined()) {
return api().serverAllowListAdd(Interop.text(arena, name)) != 0;
}
}

/**
* Removes a name and kicks the players the allow list no longer lets in.
*/
public boolean allowListRemove(String name) {
try (Arena arena = Arena.ofConfined()) {
return api().serverAllowListRemove(Interop.text(arena, name)) != 0;
}
}

public List<String> allowList() {
int count = api().serverAllowListCount();
List<String> names = new ArrayList<>(Math.max(count, 0));
for (int index = 0; index < count; index++) {
names.add(Interop.string(api().serverAllowListName(index)));
}
return names;
}

public boolean allowListEnabled() {
return api().serverAllowListEnabled() != 0;
}

public void setAllowListEnabled(boolean enabled) {
api().serverSetAllowListEnabled(enabled ? 1 : 0);
}

public String motd() {
return Interop.string(api().serverMotd());
}

/**
* The server name of the server list entry, until the server restarts; server.properties is not changed.
*/
public void setMotd(String motd) {
try (Arena arena = Arena.ofConfined()) {
api().serverSetMotd(Interop.text(arena, motd));
}
}

public int maxPlayers() {
return api().serverMaxPlayers();
}

public boolean setMaxPlayers(int maxPlayers) {
return api().serverSetMaxPlayers(maxPlayers) != 0;
}

/**
* Ticks per second over the last ticks, at most 20.
*/
public double tps() {
return api().serverTps();
}

public double millisecondsPerTick() {
return api().serverMillisecondsPerTick();
}

/**
* Stops the server after the current tick, like /stop.
*/
public void shutdown() {
api().serverShutdown();
}

public List<String> plugins() {
int count = api().serverPluginCount();
List<String> names = new ArrayList<>(Math.max(count, 0));
for (int index = 0; index < count; index++) {
names.add(Interop.string(api().serverPluginName(index)));
}
return names;
}

public Optional<String> pluginVersion(String name) {
try (Arena arena = Arena.ofConfined()) {
MemorySegment version = api().serverPluginVersion(Interop.text(arena, name));
return Interop.isNull(version) ? Optional.empty() : Optional.of(Interop.string(version));
}
}

public boolean isPluginEnabled(String name) {
try (Arena arena = Arena.ofConfined()) {
return api().serverPluginEnabled(Interop.text(arena, name)) != 0;
}
}

public Difficulty difficulty() {
return Difficulty.of(api().serverDifficulty());
}
Expand Down
112 changes: 112 additions & 0 deletions native/include/falcon/Server.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,110 @@ namespace falcon {
return detail::api().serverSetDifficulty(static_cast<FalconDifficulty>(difficulty)) != 0;
}

/** Bans a name, like /ban, and kicks the player when online; the reason is shown to them. */
static bool ban(const std::string &name, const std::string &reason = "") {
const char *source = detail::api().pluginName(detail::plugin());
return detail::api().serverBan(name.c_str(), reason.c_str(), source) != 0;
}

static bool pardon(const std::string &name) {
return detail::api().serverPardon(name.c_str()) != 0;
}

static bool isBanned(const std::string &name) {
return detail::api().serverIsBanned(name.c_str()) != 0;
}

static std::vector<std::string> bannedNames() {
return list(detail::api().serverBanCount(), detail::api().serverBannedName);
}

/** Bans an address, like /ban-ip, and kicks every player connected from it. */
static bool banIp(const std::string &address, const std::string &reason = "") {
return detail::api().serverBanIp(address.c_str(), reason.c_str(),
detail::api().pluginName(detail::plugin())) != 0;
}

static bool pardonIp(const std::string &address) {
return detail::api().serverPardonIp(address.c_str()) != 0;
}

static bool isIpBanned(const std::string &address) {
return detail::api().serverIsIpBanned(address.c_str()) != 0;
}

static std::vector<std::string> bannedIps() {
return list(detail::api().serverIpBanCount(), detail::api().serverBannedIp);
}

static bool allowListAdd(const std::string &name) {
return detail::api().serverAllowListAdd(name.c_str()) != 0;
}

/** Removes a name and kicks the players the allow list no longer lets in. */
static bool allowListRemove(const std::string &name) {
return detail::api().serverAllowListRemove(name.c_str()) != 0;
}

static std::vector<std::string> allowList() {
return list(detail::api().serverAllowListCount(), detail::api().serverAllowListName);
}

static bool allowListEnabled() {
return detail::api().serverAllowListEnabled() != 0;
}

static void setAllowListEnabled(bool enabled) {
detail::api().serverSetAllowListEnabled(enabled ? 1 : 0);
}

static std::string motd() {
return detail::text(detail::api().serverMotd());
}

/** The server name of the server list entry, until the server restarts; server.properties is not changed. */
static void setMotd(const std::string &motd) {
detail::api().serverSetMotd(motd.c_str());
}

/** The player limit, shown in the server list too. */
static uint32_t maxPlayers() {
return detail::api().serverMaxPlayers();
}

static bool setMaxPlayers(uint32_t maxPlayers) {
return detail::api().serverSetMaxPlayers(maxPlayers) != 0;
}

/** Ticks per second over the last ticks, at most 20. */
static double tps() {
return detail::api().serverTps();
}

static double millisecondsPerTick() {
return detail::api().serverMillisecondsPerTick();
}

/** Stops the server after the current tick, like /stop. */
static void shutdown() {
detail::api().serverShutdown();
}

static std::vector<std::string> plugins() {
return list(detail::api().serverPluginCount(), detail::api().serverPluginName);
}

static std::optional<std::string> pluginVersion(const std::string &name) {
const char *version = detail::api().serverPluginVersion(name.c_str());
if (version == nullptr)
return std::nullopt;
return std::string(version);
}

static bool isPluginEnabled(const std::string &name) {
return detail::api().serverPluginEnabled(name.c_str()) != 0;
}

static std::string version() {
return detail::api().serverVersion();
}
Expand Down Expand Up @@ -86,5 +190,13 @@ namespace falcon {
static bool unloadWorld(const std::string &name) {
return detail::api().serverUnloadWorld(name.c_str()) != 0;
}

private:
static std::vector<std::string> list(uint32_t count, const char *(*at)(uint32_t)) {
std::vector<std::string> values;
for (uint32_t index = 0; index < count; ++index)
values.push_back(detail::text(at(index)));
return values;
}
};
}
28 changes: 28 additions & 0 deletions native/include/falcon/falcon_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -739,6 +739,34 @@ typedef struct FalconServerApi {
void (*playerClearCamera)(FalconPlayer *player);
int32_t (*playerItemCooldown)(FalconPlayer *player, FalconItem *item);
int (*playerStartItemCooldown)(FalconPlayer *player, FalconItem *item, int32_t ticks);

int (*serverBan)(const char *name, const char *reason, const char *source);
int (*serverPardon)(const char *name);
int (*serverIsBanned)(const char *name);
uint32_t (*serverBanCount)(void);
const char *(*serverBannedName)(uint32_t index);
int (*serverBanIp)(const char *address, const char *reason, const char *source);
int (*serverPardonIp)(const char *address);
int (*serverIsIpBanned)(const char *address);
uint32_t (*serverIpBanCount)(void);
const char *(*serverBannedIp)(uint32_t index);
int (*serverAllowListAdd)(const char *name);
int (*serverAllowListRemove)(const char *name);
uint32_t (*serverAllowListCount)(void);
const char *(*serverAllowListName)(uint32_t index);
int (*serverAllowListEnabled)(void);
void (*serverSetAllowListEnabled)(int enabled);
const char *(*serverMotd)(void);
void (*serverSetMotd)(const char *motd);
uint32_t (*serverMaxPlayers)(void);
int (*serverSetMaxPlayers)(uint32_t maxPlayers);
double (*serverTps)(void);
double (*serverMillisecondsPerTick)(void);
void (*serverShutdown)(void);
uint32_t (*serverPluginCount)(void);
const char *(*serverPluginName)(uint32_t index);
const char *(*serverPluginVersion)(const char *name);
int (*serverPluginEnabled)(const char *name);
} FalconServerApi;

typedef int (*FalconPluginEntry)(const FalconServerApi *api, FalconPlugin *plugin, FalconPluginCallbacks *callbacks);
Expand Down
29 changes: 29 additions & 0 deletions wasm/falcon.wit
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,35 @@ interface server {
/// One of the `FALCON_DIFFICULTY_*` values.
server-difficulty: func() -> u32;
server-set-difficulty: func(difficulty: u32) -> bool;
/// Kicks the player when online, like /ban; `source` is the name recorded as the one who banned.
server-ban: func(name: string, reason: string, source: string) -> bool;
server-pardon: func(name: string) -> bool;
server-is-banned: func(name: string) -> bool;
server-ban-count: func() -> u32;
server-banned-name: func(index: u32) -> option<string>;
server-ban-ip: func(address: string, reason: string, source: string) -> bool;
server-pardon-ip: func(address: string) -> bool;
server-is-ip-banned: func(address: string) -> bool;
server-ip-ban-count: func() -> u32;
server-banned-ip: func(index: u32) -> option<string>;
server-allow-list-add: func(name: string) -> bool;
server-allow-list-remove: func(name: string) -> bool;
server-allow-list-count: func() -> u32;
server-allow-list-name: func(index: u32) -> option<string>;
server-allow-list-enabled: func() -> bool;
server-set-allow-list-enabled: func(enabled: bool);
/// The server name of the server list entry; server.properties is not changed.
server-motd: func() -> string;
server-set-motd: func(motd: string);
server-max-players: func() -> u32;
server-set-max-players: func(max-players: u32) -> bool;
server-tps: func() -> f64;
server-milliseconds-per-tick: func() -> f64;
server-shutdown: func();
server-plugin-count: func() -> u32;
server-plugin-name: func(index: u32) -> option<string>;
server-plugin-version: func(name: string) -> option<string>;
server-plugin-enabled: func(name: string) -> bool;
}

interface players {
Expand Down
Loading