bdlauncher icon indicating copy to clipboard operation
bdlauncher copied to clipboard

[Idea] New Command Register Interface

Open codehz opened this issue 6 years ago • 10 comments

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)

codehz avatar Jan 13 '20 12:01 codehz

@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 avatar Jan 13 '20 13:01 ghost

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

ghost avatar Jan 13 '20 13:01 ghost

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 avatar Jan 13 '20 13:01 codehz

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

codehz avatar Jan 13 '20 13:01 codehz

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

ghost avatar Jan 13 '20 13:01 ghost

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..

codehz avatar Jan 13 '20 13:01 codehz

@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 avatar Jan 13 '20 14:01 ghost

@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 avatar Jan 14 '20 05:01 ghost

@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)

ghost avatar Jan 14 '20 06:01 ghost

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) {}
....

codehz avatar Jan 14 '20 07:01 codehz