BDLDev / bdlauncher

BedRockServer launcher with mods support
Other
123 stars 34 forks source link

[Idea] New Command Register Interface #54

Open codehz opened 4 years ago

codehz commented 4 years ago

Concept:

CustomCommandResult teleport_to_player(CommandOrigin &origin, ServerPlayer *target) {
// IMPL
}
CustomCommandResult teleport_to_pos(CommandOrigin &origin, Vec3 target) {
// IMPL
}
// register
BDLCommandRegistry.register("teleport", teleport_to_player, teleport_to_pos);

Note: the pattern of the command is CustomCommandResult (*)(CommandOrigin &origin, T... t)

ghost commented 4 years ago

@codehz What about void teleport_to_player(CommandOriginHelper&/Helper class for access to BDS CommandOrigin/ origin,CustomCommandResult& res,ServerPlayer sp){ //origin.getPlayer returns ServerPlayer if(!origin.isPlayer()){ res.error(); res<<"error "<<123<<origin.getName(); //overloaded << operator } } BDLCMDRegistry::registerCommand("tpa",overload1/Infer arguments automatically /,overload2,if_no_overload_found_handler);

ghost commented 4 years ago

@codehz and could you please show how to register a command with enum? like /tpa {accept,deny},etc.

codehz commented 4 years ago

to register enum:

enum class MyEnum: int {A, B};
auto test = BDLCommandRegistry::newEnum<MyEnum>("test");
test.add("A", MyEnum::A);
test.add("B", MyEnum::B);

dynamic enum:

// in global scope
static auto test = BDLCommandRegistry::newDynamicEnum<decltype("test_dynamic"_dynenum)>(); // use gcc extension to generate type from string
// in some function
test.set({"A", "B"});
test.clear();
test.add("C");

and a better command register method:

auto command = BDLCommandRegistry::newCommand("command");
command.add(impl_01);
command.add(impl_02);
command.set_fallback(if_no_overload_found_handler); // I'm not sure if it can be implemented...
codehz commented 4 years ago

maybe we should use codegen insteads of just template meta programming... or the argument name cannot be inferred from function.. (and optional argument)

ghost commented 4 years ago

@codehz yeah,you're right. I wonder whether overload will be called,if no suitable overload is found. like this. /tpa <{to,from}:enum> /tpa <--- will be called when "/tpa wrong usage xxxx"

codehz commented 4 years ago

BTW, the command parsing is happened in server side.. so the malformed command expression would be able to detect in server side and rerouting to fallback handler.. seems pointless..

ghost commented 4 years ago

@codehz using mojang command overload api seems like a morr complex way to solve problem(need to generate class and vtable dynamically(or need a codegen),need to reverse-engineer more api). Use a simple lexer with overload support maybe a better choice? Maybe we can use tricks to make client show overloads,like multi-line command description.(hadnt tested)

ghost commented 4 years ago

@codehz I dont know if duplicated availableCommandsPacket with only one command works well.(it means sending overloads of a mod commands after server sent previous availableCommandsPacket to client ) Modifing availableCommandsPacket::write seems like a difficult job.

ghost commented 4 years ago

@codehz @CodeHz new idea:

void tpa_to_impl(...,ServerPlayer* sp,int xx){

}
CommandBase cmd("tpa");
cmd.overload("to <dest:player> <testval:int>",tpa_to_impl);//use template like overload(string_view,void(*)(...,T ,T2) to determine how many arguments need to be parsed(in base.h) and base.so just exports regCommand0(sview,void *function),regCommand1...,etc..
and lexer parses overload,and do some preparations(convert string to int,ServerPlayer*,etc)
and use (void(*)(...,void*,void*))callback(arg0,arg1,argx)

CONS : 1.assume that all arguments are 64bits long.(so passing string_view and const string(abi:cxx11) cant work?(because string_view uses two registers).And float cant work ad well(because it uses %xmm0 register) ) 2.use a lot of else if to make right calls(right counts of arguments)

codehz commented 4 years ago

alternative concept: for codegen

// header (.h)
struct Teleport : CustomCommandDescription {
static constexpr auto name = "teleport";
static constexpr auto permission = CommandPermission::OP;
// any name
void impl_01(ServerPlayer *target); // generate `teleport <target: player>`
// use std::optional for optional argument
void impl_02(Vec3 pos, std::optional<int> angle);  // generate `teleport <pos: position> [angle: int]`
// use enum
void impl_03(MyEnum target);  // generate `teleport <target: my_enum>`
};
extern "C" {
BDL_EXPORT int mod_register_command(CommandRegistry *); // codegen
}
// impl (.cpp)
void Teleport::impl_01(ServerPlayer *target) {}
....