Skip to content

Commit

Permalink
Merge pull request #213 from sakurawald/dev
Browse files Browse the repository at this point in the history
bump: v5.0.0
  • Loading branch information
sakurawald authored Oct 30, 2024
2 parents 442fc19 + 82a2c2b commit ff1aa04
Show file tree
Hide file tree
Showing 59 changed files with 470 additions and 174 deletions.
19 changes: 13 additions & 6 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
> The version number of fuji follows `semver` now: https://semver.org/
> The version number of fuji follows `semver` now: https://semver.org/
- feature: add `on_warped` event for warps. (command_toolbox.warp module)
- fix: possible to trigger `Not a JSON Object: null` when a new fake-player is spawned via `carpet` mod. (placeholder module)
- fix: can't display a specific type of block entity properly, e.g. beds, banners etc. (chunks module)
- refactor: cleanup unused functions in core, rename and simplify symbols in core.
> This version includes the following **breaking changes** if you are using them:
> - feature: add `others` literal arguments to most commands that only targeted at command source player in the past,
now allows to use `others` argument to apply the command to a collection of players. This influence the following
commands (**If you are using `command_permission module` with `apply-sponge-implicit-wildcard=false`
in `luckperms.conf`, then everything is fine. If the option is true, then be careful that the `wildcard permission`
may allow players to use the following commands with `others` option.**):
> - all functional commands.
> - most of the commands in `command_toolbox`
> - /afk, /back, /chat style, /pvp, /rtp
> - The command option `/tppos --targetPlayer ...` is replaced by `/tppos others ...`. (command_toolbox.tppos module)
> - make the default required level permission to 4: /heal, /ping, /extinguish, /near (command_toolbox.* module)
> - make the default required level permission to 4: all functional commands. (functional module)
3 changes: 1 addition & 2 deletions TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,4 @@
- list operations
- json operations
- text operation
- application: /air, /alert, /respawn, /vote
- feature: add @CommandTarget annotation
- application: /air, /alert, /respawn, /vote
2 changes: 1 addition & 1 deletion crowdin/id_ID.json
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@
"command_cooldown.not_found": "<red>Cooldown %s tidak ditemukan.",
"command_cooldown.already_exists": "<red>Cooldown %s sudah ada.",
"command_cooldown.deleted": "<red>Cooldown %s dihapus.",
"command_cooldown.created": "<green>The cooldown `%s` created.",
"command_cooldown.created": "<green>Cooldown `%s` telah dibuat.",
"echo.send_custom.custom_text.not_found": "<red>Teks khusus %s tidak ditemukan.",
"echo.send_custom.custom_text.invalid_page": "<red>Halaman tidak valid.",
"echo.send_custom.custom_text.paginator.first_page": "<dark_green>-----<< <grey><hover:show_text:'Ini adalah halaman pertama'>Sebelumnya</grey> <green>%d<grey>/<green>%d <orange>click:run_command:'%s'<hover:show_text:'Halaman Berikutnya'>Berikutnya</hover></click></orange><dark_green> >>----",
Expand Down
2 changes: 1 addition & 1 deletion crowdin/zh_TW.json
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@
"command_cooldown.not_found": "<red>找不到冷卻時間 %s。",
"command_cooldown.already_exists": "<red>冷卻時間 %s 已存在。",
"command_cooldown.deleted": "<red>已刪除冷卻時間 %s。",
"command_cooldown.created": "<green>The cooldown `%s` created.",
"command_cooldown.created": "<green>已建立冷卻時間 %s。",
"echo.send_custom.custom_text.not_found": "<red>找不到自訂文字 %s。",
"echo.send_custom.custom_text.invalid_page": "<red>無效的頁面。",
"echo.send_custom.custom_text.paginator.first_page": "<dark_green>-----<< <grey><hover:show_text:'這是第一頁'>上一頁</grey> <green>%d<grey>/<green>%d <orange><click:run_command:'%s'><hover:show_text:'下一頁'>下一頁</hover></click></orange><dark_green> >>----",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@
or \cmd{/fuji inspect server-commands}
\end{tips}

\begin{warn}{Understand the parent permission node and its children node}
It's recommend to modify the \ttt{apply-sponge-implicit-wildcard} option to \ttt{false} in \ttt{luckperms.conf}, to control the \ttt{permission node} more fine-grained.
\end{warn}

\LevelTwo{Example}
\begin{example}{Allow everyone to use \cmd{/gamemode} command}
\cmd{/lp group default permission set fuji.permission.gamemode true}
Expand Down
10 changes: 5 additions & 5 deletions docs/chapters/qna/qna.tex
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,13 @@

\LevelOne{Can I ask the forge or neoforge support?}
We have no plan for forge or neoforge platform.However, you can try running this mod via \tbf{sinytra-connector} mod.
It's tested the mod works in the following environment (104/104 modules works):
It's tested the mod works in the following environment (105/105 modules works):
\begin{shcode}
Loader: NeoForge v21.0.167 for Minecraft 1.21
Loader: NeoForge v21.1.73:server for Minecraft 1.21.1
Mods:
- connector-2.0.0-beta.1+1.21-full
- forgified-fabric-api-0.101.2+2.0.10+1.21
- fuji-1.6.3-release-1914a82a84
- connector-2.0.0-beta.3+1.21.1-full.jar
- forgified-fabric-api-0.104.0+2.0.15+1.21.1.jar
- fuji-4.3.0-5518b05201-mc1.21.jar
\end{shcode}

\LevelOne{How can I report bugs or suggest new features?}
Expand Down
Binary file modified docs/release/fuji.pdf
Binary file not shown.
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ org.gradle.parallel=true
# project
maven_group=io.github.sakurawald
mod_id=fuji
mod_version=4.3.0
mod_version=5.0.0

# loader
minecraft_version=1.21.2
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package io.github.sakurawald.core.command.annotation;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
public @interface CommandTarget {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package io.github.sakurawald.core.command.argument.adapter.impl;

import com.mojang.brigadier.arguments.ArgumentType;
import com.mojang.brigadier.context.CommandContext;
import io.github.sakurawald.core.command.argument.adapter.abst.BaseArgumentTypeAdapter;
import io.github.sakurawald.core.command.argument.structure.Argument;
import io.github.sakurawald.core.command.argument.wrapper.impl.PlayerCollection;
import lombok.SneakyThrows;
import net.minecraft.command.argument.EntityArgumentType;
import net.minecraft.server.command.ServerCommandSource;

import java.util.List;

public class PlayerCollectionArgumentTypeAdapter extends BaseArgumentTypeAdapter {
@Override
protected ArgumentType<?> makeArgumentType() {
return EntityArgumentType.players();
}

@SneakyThrows
@Override
protected Object makeArgumentObject(CommandContext<ServerCommandSource> context, Argument argument) {
return new PlayerCollection(EntityArgumentType.getPlayers(context, argument.getArgumentName()));
}

@Override
public List<Class<?>> getTypeClasses() {
return List.of(PlayerCollection.class);
}

@Override
public List<String> getTypeStrings() {
return List.of("players", "player-list");
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
package io.github.sakurawald.core.command.argument.structure;

import io.github.sakurawald.core.annotation.Document;
import io.github.sakurawald.core.command.annotation.CommandSource;
import io.github.sakurawald.core.command.annotation.CommandTarget;
import io.github.sakurawald.core.command.structure.CommandRequirementDescriptor;
import lombok.Getter;
import net.minecraft.server.network.ServerPlayerEntity;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.lang.reflect.Parameter;

/**
* Rules:
* - There are 2 kinds of Argument: LiteralArgument and RequiredArgument.
Expand All @@ -16,35 +21,32 @@
*/
@Getter
public class Argument {
private static final String REQUIRED_ARGUMENT_PLACEHOLDER = "$";
private static final int THE_METHOD_PARAMETER_INDEX_FOR_LITERAL_ARGUMENT = -1;

final Class<?> type;
final String argumentName;
final @Nullable Class<?> type;
final @NotNull String argumentName;
final boolean isOptional;
final CommandRequirementDescriptor requirement;
int methodParameterIndex;
final @Nullable CommandRequirementDescriptor requirement;
boolean isCommandSource;

// this field is only used for RetargetCommandDescriptor
boolean isCommandTarget;

@Nullable String document;

private Argument(@Nullable Class<?> type, @NotNull String argumentName, int methodParameterIndex, boolean isOptional, @Nullable CommandRequirementDescriptor requirement) {
private Argument(@Nullable Class<?> type, @NotNull String argumentName, boolean isOptional, @Nullable CommandRequirementDescriptor requirement) {
this.type = type;
this.argumentName = argumentName;
this.methodParameterIndex = methodParameterIndex;
this.isOptional = isOptional;
this.requirement = requirement;

// if it's a required argument placeholder...
this.methodParameterIndex = this.tryParseMethodParameterIndexFromArgumentName();
}

public static Argument makeRequiredArgument(@Nullable Class<?> type, @NotNull String argumentName, int methodParameterIndex, boolean isOptional, @Nullable CommandRequirementDescriptor requirement) {
return new Argument(type, argumentName, methodParameterIndex, isOptional, requirement);
public static Argument makeRequiredArgument(@NotNull Class<?> type, @NotNull String argumentName, boolean isOptional, @Nullable CommandRequirementDescriptor requirement) {
return new Argument(type, argumentName, isOptional, requirement);
}

public static Argument makeLiteralArgument(@NotNull String argumentName, @Nullable CommandRequirementDescriptor requirement) {
return new Argument(null, argumentName, THE_METHOD_PARAMETER_INDEX_FOR_LITERAL_ARGUMENT, false, requirement);
return new Argument(null, argumentName, false, requirement);
}

public Argument withDocument(@Nullable Document document) {
Expand All @@ -55,18 +57,14 @@ public Argument withDocument(@Nullable Document document) {
}

public boolean isRequiredArgument() {
// A literal argument doesn't need to get the value from the parameter in the method.
// A required argument needs to get the value from the parameter in the method, so the index >= 0.
return this.methodParameterIndex >= 0;
// the type for literal argument is always null.
return this.type != null;
}

public boolean isLiteralArgument() {
return !this.isRequiredArgument();
}

public boolean isRequiredArgumentPlaceholder() {
return this.argumentName.startsWith(REQUIRED_ARGUMENT_PLACEHOLDER);
}

private String computeRequirementString() {
if (this.requirement != null) {
Expand All @@ -79,51 +77,65 @@ private String computeRequirementString() {

@Override
public String toString() {
// command source
String commandSourceString = this.isCommandSource ? "@" : "";

/* required argument */
String flags = "";
if (this.isCommandSource) flags += "S";
if (this.isCommandTarget) flags += "T";

if (this.isRequiredArgument()) {
if (isOptional) {
return commandSourceString + "[%s $%d]{%s}".formatted(this.argumentName, this.methodParameterIndex, this.computeRequirementString());
return "[%s](%s){%s}".formatted(this.argumentName, flags, this.computeRequirementString());
} else {
return commandSourceString + "<%s $%d>{%s}".formatted(this.argumentName, this.methodParameterIndex, this.computeRequirementString());
return "<%s>(%s){%s}".formatted(this.argumentName, flags, this.computeRequirementString());
}
}

/* literal argument */
return "%s{%s}".formatted(this.argumentName, this.computeRequirementString());
}

public String toInGameString() {
public String toHumanReadableString() {
if (this.isLiteralArgument()) {
return this.argumentName;
}

// the type is only null if this is a literal argument.
assert this.getType() != null;
if (isOptional) {
return "[%s %s]".formatted(this.argumentName, this.getType().getSimpleName());
} else {
return "<%s %s>".formatted(this.argumentName, this.getType().getSimpleName());
}
}

private int tryParseMethodParameterIndexFromArgumentName() {
// parse the method parameter index
if (argumentName.startsWith(REQUIRED_ARGUMENT_PLACEHOLDER)) {
this.methodParameterIndex = Integer.parseInt(argumentName.substring(REQUIRED_ARGUMENT_PLACEHOLDER.length()));
}

return methodParameterIndex;
public Argument markWithParameter(Parameter parameter) {
this.markAsCommandSourceWithParameter(parameter);
this.markAsCommandTargetWithParameter(parameter);
return this;
}

public Argument markAsCommandSource() {
private Argument markAsCommandSourceWithParameter(Parameter parameter) {
if (!parameter.isAnnotationPresent(CommandSource.class)) return this;

if (!this.isRequiredArgument())
throw new IllegalArgumentException("The argument for command source must be a required argument.");
if (this.getType() == null)
throw new IllegalArgumentException("The type of the argument for command source must not null.");

this.isCommandSource = true;
return this;
}

private Argument markAsCommandTargetWithParameter(Parameter parameter) {
if (!parameter.isAnnotationPresent(CommandTarget.class)) return this;

if (!this.isRequiredArgument())
throw new IllegalArgumentException("The argument for command target must be a required argument.");

if (!parameter.getType().equals(ServerPlayerEntity.class)) {
throw new IllegalArgumentException("the annotation @CommandTarget can only be used in a parameter whose type is ServerPlayerEntity: class = %s, method = %s".formatted(parameter.getDeclaringExecutable().getName(), parameter.getDeclaringExecutable().getDeclaringClass().getSimpleName()));
}

this.isCommandTarget = true;
return this;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package io.github.sakurawald.core.command.argument.wrapper.impl;

import io.github.sakurawald.core.command.argument.wrapper.abst.SingularValue;
import net.minecraft.server.network.ServerPlayerEntity;

import java.util.Collection;

public class PlayerCollection extends SingularValue<Collection<ServerPlayerEntity>> {
public PlayerCollection(Collection<ServerPlayerEntity> value) {
super(value);
}
}
Loading

0 comments on commit ff1aa04

Please sign in to comment.