diff options
Diffstat (limited to 'mcin.c')
-rw-r--r-- | mcin.c | 425 |
1 files changed, 425 insertions, 0 deletions
@@ -0,0 +1,425 @@ +#include "mcin.h" +#include "common.h" +#include "thpool.h" +#include "plugins.h" +#include "plugin_registry.h" + +#include <regex.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <stdbool.h> + +static regex_t reg_master; + +static regex_t reg_player_join; +static regex_t reg_player_leave; +static regex_t reg_player_achievement; +static regex_t reg_player_challenge; +static regex_t reg_player_goal; +static regex_t reg_player_say; + +static regex_t reg_player_die[64]; + +static regex_t reg_server_stopping; +static regex_t reg_server_starting; +static regex_t reg_server_started; + +static int mcin_compile_regex(const char *regex, const int flags, regex_t *reg) +{ + int r = regcomp(reg, regex, flags); + if(r) + { + fprintf(stderr, _("Cannot compile regex: %s.\n"), regex); + } + return r; +} + +#define mcin_compile_death_msg(index, regex) \ +{ \ + r = mcin_compile_regex(regex, REG_EXTENDED, ®_player_die[index]); \ + if(r) return r; \ +} + +int mcin_init() +{ + int r = 0; + r = mcin_compile_regex(".*\\[([0-9][0-9]:[0-9][0-9]:[0-9][0-9])\\] \\[(.*)\\/(.*)\\]: (.*)\n", REG_EXTENDED, ®_master); + if(r) return r; + r = mcin_compile_regex("(.*) joined the game", REG_EXTENDED, ®_player_join); + if(r) return r; + r = mcin_compile_regex("(.*) lost connection: (.*)", REG_EXTENDED, ®_player_leave); + if(r) return r; + r = mcin_compile_regex("(.*) has made the advancement \\[(.*)\\]", REG_EXTENDED, ®_player_achievement); + if(r) return r; + r = mcin_compile_regex("(.*) has completed the challenge \\[(.*)\\]", REG_EXTENDED, ®_player_challenge); + if(r) return r; + r = mcin_compile_regex("(.*) has reached the goal \\[(.*)\\]", REG_EXTENDED, ®_player_goal); + if(r) return r; + r = mcin_compile_regex("<(.*)> (.*)", REG_EXTENDED, ®_player_say); + if(r) return r; + + r = mcin_compile_regex("Stopping server", REG_EXTENDED, ®_server_stopping); + if(r) return r; + r = mcin_compile_regex("Starting minecraft server version (.*)", REG_EXTENDED, ®_server_starting); + if(r) return r; + r = mcin_compile_regex("Done \\((.*s)\\)! For help, type \"help\"", REG_EXTENDED, ®_server_started); + if(r) return r; + + mcin_compile_death_msg(0, "(.*) was shot by (.*)"); + mcin_compile_death_msg(1, "(.*) was shot by (.*) using .*"); + mcin_compile_death_msg(2, "(.*) was pummeled by (.*)"); + mcin_compile_death_msg(3, "(.*) was pummeled by (.*) using .*"); + mcin_compile_death_msg(4, "(.*) was pricked to death"); + mcin_compile_death_msg(5, "(.*) walked into a cactus whilst trying to escape (.*)"); + mcin_compile_death_msg(6, "(.*) drowned"); + mcin_compile_death_msg(7, "(.*) drowned whilst trying to escape (.*)"); + mcin_compile_death_msg(8, "(.*) experienced kinetic energy"); + mcin_compile_death_msg(9, "(.*) experienced kinetic energy whilst trying to escape (.*)"); + mcin_compile_death_msg(10, "(.*) was blown up by (.*)"); + mcin_compile_death_msg(11, "(.*) was blown up by (.*) using .*"); + mcin_compile_death_msg(12, "(.*) was killed by \\[Intentional Game Design\\]"); + mcin_compile_death_msg(13, "(.*) hit the ground too hard"); + mcin_compile_death_msg(14, "(.*) hit the ground too hard whilst trying to escape (.*)"); + mcin_compile_death_msg(15, "(.*) fell from a high place"); + mcin_compile_death_msg(16, "(.*) fell off a ladder"); + mcin_compile_death_msg(17, "(.*) fell off some vines"); + mcin_compile_death_msg(18, "(.*) fell off some weeping vines"); + mcin_compile_death_msg(19, "(.*) fell off some twisting vines"); + mcin_compile_death_msg(20, "(.*) fell off scaffolding"); + mcin_compile_death_msg(21, "(.*) fell off while climbing"); + mcin_compile_death_msg(22, "(.*) was squashed by a falling anvil"); + mcin_compile_death_msg(23, "(.*) was squashed by a falling anvil whilst fighting (.*)"); + mcin_compile_death_msg(24, "(.*) was squashed by a falling block"); + mcin_compile_death_msg(25, "(.*) was squashed by a falling block whilst fighting (.*)"); + mcin_compile_death_msg(26, "(.*) went up in flames"); + mcin_compile_death_msg(27, "(.*) walked into fire whilst fighting (.*.)"); + mcin_compile_death_msg(28, "(.*) burned to death"); + mcin_compile_death_msg(29, "(.*) was burnt to a crisp whilst fighting (.*)"); + mcin_compile_death_msg(30, "(.*) went off with a bang"); + mcin_compile_death_msg(31, "(.*) went off with a bang due to a firework fired from .* by (.*)"); + mcin_compile_death_msg(32, "(.*) tried to swim in lava"); + mcin_compile_death_msg(33, "(.*) tried to swim in lava to escape (.*)"); + mcin_compile_death_msg(34, "(.*) was struck by lightning"); + mcin_compile_death_msg(35, "(.*) was struck by lightning whilst fighting (.*)"); + mcin_compile_death_msg(36, "(.*) discovered the floor was lava"); + mcin_compile_death_msg(37, "(.*) walked into danger zone due to (.*)"); + mcin_compile_death_msg(38, "(.*) was killed by magic"); + mcin_compile_death_msg(39, "(.*) was killed by magic whilst trying to escape (.*)"); + mcin_compile_death_msg(40, "(.*) was killed by (.*) using magic"); + mcin_compile_death_msg(41, "(.*) was killed by (.*) using .*"); + mcin_compile_death_msg(42, "(.*) was slain by (.*)"); + mcin_compile_death_msg(43, "(.*) was slain by (.*) using .*"); + mcin_compile_death_msg(44, "(.*) was fireballed by (.*)"); + mcin_compile_death_msg(45, "(.*) was fireballed by (.*) using .*"); + mcin_compile_death_msg(46, "(.*) was stung to death"); + mcin_compile_death_msg(47, "(.*) was shot by a skull from (.*)"); + mcin_compile_death_msg(48, "(.*) starved to death"); + mcin_compile_death_msg(49, "(.*) starved to death whilst fighting (.*)"); + mcin_compile_death_msg(50, "(.*) suffocated in a wall"); + mcin_compile_death_msg(51, "(.*) suffocated in a wall whilst fighting (.*)"); + mcin_compile_death_msg(52, "(.*) was squished too much"); + mcin_compile_death_msg(53, "(.*) was squished by (.*)"); + mcin_compile_death_msg(54, "(.*) was poked to death by a sweet berry bush"); + mcin_compile_death_msg(55, "(.*) was poked to death by a sweet berry bush whilst trying to escape (.*)"); + mcin_compile_death_msg(56, "(.*) was killed trying to hurt (.*)"); + mcin_compile_death_msg(57, "(.*) was killed by .* trying to hurt (.*)"); + mcin_compile_death_msg(58, "(.*) was impaled by (.*)"); + mcin_compile_death_msg(59, "(.*) was impaled by (.*) with .*"); + mcin_compile_death_msg(60, "(.*) fell out of the world"); + mcin_compile_death_msg(61, "(.*) didn't want to live in the same world as (.*)"); + mcin_compile_death_msg(62, "(.*) withered away"); + mcin_compile_death_msg(63, "(.*) withered away whilst fighting (.*)"); + + return r; +} + +void mcin_free() +{ + regfree(®_master); + regfree(®_player_join); + regfree(®_player_leave); + regfree(®_player_say); + regfree(®_player_achievement); + regfree(®_player_challenge); + regfree(®_player_goal); + for(int i = 0; i < 64; i ++) + regfree(®_player_die[i]); + regfree(®_server_stopping); + regfree(®_server_starting); + regfree(®_server_started); +} + +static bool mcin_match_one_ex(const regex_t reg, const char *str, const int required_args, const int total_args, struct plugin_call_job_args *arg) +{ + regmatch_t pmatch[6]; + int r = regexec(®, str, 6, pmatch, 0); + if(r) + { + return false; + } + if(pmatch[0].rm_so == -1) return false; + arg->id = 0; + arg->arg1 = NULL; + arg->arg2 = NULL; + arg->arg3 = NULL; + arg->arg4 = NULL; + arg->arg5 = NULL; + for(int i = 1; i < total_args + 1; i ++) + { + const regmatch_t match = pmatch[i]; + if(match.rm_so == -1 && i < required_args) + { + // Not reaching the required number of arguments. + if(arg->arg5 != NULL) + { + free(arg->arg5); + arg->arg5 = NULL; + } + if(arg->arg4 != NULL) + { + free(arg->arg4); + arg->arg4 = NULL; + } + if(arg->arg3 != NULL) + { + free(arg->arg3); + arg->arg3 = NULL; + } + if(arg->arg2 != NULL) + { + free(arg->arg2); + arg->arg2 = NULL; + } + if(arg->arg1 != NULL) + { + free(arg->arg1); + arg->arg1 = NULL; + } + return false; + } + const int length = match.rm_eo - match.rm_so; + char *substring = calloc(length + 1, sizeof(char)); + memcpy(substring, &str[match.rm_so], length); + substring[length] = '\0'; + switch(i) + { + case 1: + arg->arg1 = substring; + break; + case 2: + arg->arg2 = substring; + break; + case 3: + arg->arg3 = substring; + break; + case 4: + arg->arg4 = substring; + break; + case 5: + arg->arg5 = substring; + break; + } + } + return true; +} + +static bool mcin_match_one(const regex_t reg, const char *str, const int required_args, struct plugin_call_job_args *arg) +{ + return mcin_match_one_ex(reg, str, required_args, required_args, arg); +} + +static struct plugin_call_job_args *args_copy(const struct plugin_call_job_args *orig, int index) +{ + struct plugin_call_job_args *args = malloc(sizeof(struct plugin_call_job_args)); + args->id = index; // Index to ID resolution will happen in plugcall_*. + if(orig->arg1 == NULL) args->arg1 = NULL; + else + { + args->arg1 = calloc(strlen(orig->arg1) + 1, sizeof(char)); + strcpy(args->arg1, orig->arg1); + } + + if(orig->arg2 == NULL) args->arg2 = NULL; + else + { + args->arg2 = calloc(strlen(orig->arg2) + 1, sizeof(char)); + strcpy(args->arg2, orig->arg2); + } + if(orig->arg3 == NULL) args->arg3 = NULL; + else + { + args->arg3 = calloc(strlen(orig->arg3) + 1, sizeof(char)); + strcpy(args->arg3, orig->arg3); + } + if(orig->arg4 == NULL) args->arg4 = NULL; + else + { + args->arg4 = calloc(strlen(orig->arg4) + 1, sizeof(char)); + strcpy(args->arg4, orig->arg4); + } + if(orig->arg5 == NULL) args->arg5 = NULL; + else + { + args->arg5 = calloc(strlen(orig->arg5) + 1, sizeof(char)); + strcpy(args->arg5, orig->arg5); + } + return args; +} + +void mcin_match(const char *str, const threadpool thpool) +{ + struct plugin_call_job_args local; + local.id = 0; + local.arg1 = NULL; + local.arg2 = NULL; + local.arg3 = NULL; + local.arg4 = NULL; + local.arg5 = NULL; + regmatch_t pmatch[5]; + if(regexec(®_master, str, 5, pmatch, 0)) return; + char *temp_str = calloc(strlen(str) + 1, sizeof(char)); + for(int i = 1 /* Ignore the string itself */; i < 5; i ++) + { + const regmatch_t match = pmatch[i]; + if(match.rm_so == -1) + // Shouldn't happen if the string is valid. + goto cleanup; + if(i != 2 && i != 3 && i != 4) continue; // We don't care. + int length = match.rm_eo - match.rm_so; + for(int j = 0; j < length; j ++) + { + temp_str[j] = str[match.rm_so + j]; + } + temp_str[length] = '\0'; + + if(i == 2) /* Tag */ + if(strcmp(temp_str, "Server thread")) + goto cleanup; + if(i == 3) /* Level */ + if(strcmp(temp_str, "INFO")) + goto cleanup; + if(i == 4) // Data + break; + } + const int size = plugin_size(); + if(mcin_match_one(reg_player_join, temp_str, 1, &local)) + { + for(int i = 0; i < size; i ++) + { + if(plugin_get_by_index(i)->fc_player_join == NULL) continue; + thpool_add_work(thpool, &plugcall_player_join, args_copy(&local, i)); + } + goto cleanup; + } + if(mcin_match_one(reg_player_leave, temp_str, 2, &local)) + { + for(int i = 0; i < size; i ++) + { + if(plugin_get_by_index(i)->fc_player_leave == NULL) continue; + thpool_add_work(thpool, &plugcall_player_leave, args_copy(&local, i)); + } + goto cleanup; + } + if(mcin_match_one(reg_player_achievement, temp_str, 2, &local)) + { + for(int i = 0; i < size; i ++) + { + if(plugin_get_by_index(i)->fc_player_achievement == NULL) continue; + thpool_add_work(thpool, &plugcall_player_achievement, args_copy(&local, i)); + } + goto cleanup; + } + if(mcin_match_one(reg_player_challenge, temp_str, 2, &local)) + { + for(int i = 0; i < size; i ++) + { + if(plugin_get_by_index(i)->fc_player_challenge == NULL) continue; + thpool_add_work(thpool, &plugcall_player_challenge, args_copy(&local, i)); + } + goto cleanup; + } + if(mcin_match_one(reg_player_goal, temp_str, 2, &local)) + { + for(int i = 0; i < size; i ++) + { + if(plugin_get_by_index(i)->fc_player_goal == NULL) continue; + thpool_add_work(thpool, &plugcall_player_goal, args_copy(&local, i)); + } + goto cleanup; + } + if(mcin_match_one(reg_player_say, temp_str, 2, &local)) + { + for(int i = 0; i < size; i ++) + { + if(plugin_get_by_index(i)->fc_player_say == NULL) continue; + thpool_add_work(thpool, &plugcall_player_say, args_copy(&local, i)); + } + goto cleanup; + } + for(int i = 0; i < 64; i ++) + if(mcin_match_one_ex(reg_player_die[i], temp_str, 1, 2, &local)) + { + for(int j = 0; j < size; j ++) + { + if(plugin_get_by_index(i)->fc_player_die == NULL) continue; + thpool_add_work(thpool, &plugcall_player_die, args_copy(&local, j)); + } + goto cleanup; + } + if(mcin_match_one(reg_server_stopping, temp_str, 0, &local)) + { + for(int i = 0; i < size; i ++) + { + if(plugin_get_by_index(i)->fc_server_stopping == NULL) continue; + thpool_add_work(thpool, &plugcall_server_stopping, args_copy(&local, i)); + } + goto cleanup; + } + if(mcin_match_one(reg_server_starting, temp_str, 1, &local)) + { + for(int i = 0; i < size; i ++) + { + if(plugin_get_by_index(i)->fc_server_starting == NULL) continue; + thpool_add_work(thpool, &plugcall_server_starting, args_copy(&local, i)); + } + goto cleanup; + } + if(mcin_match_one(reg_server_started, temp_str, 1, &local)) + { + for(int i = 0; i < size; i ++) + { + if(plugin_get_by_index(i)->fc_server_started == NULL) continue; + thpool_add_work(thpool, &plugcall_server_started, args_copy(&local, i)); + } + goto cleanup; + } + goto cleanup; +cleanup: + if(local.arg5 != NULL) + { + free(local.arg5); + local.arg5 = NULL; + } + if(local.arg4 != NULL) + { + free(local.arg4); + local.arg4 = NULL; + } + if(local.arg3 != NULL) + { + free(local.arg3); + local.arg3 = NULL; + } + if(local.arg2 != NULL) + { + free(local.arg2); + local.arg2 = NULL; + } + if(local.arg1 != NULL) + { + free(local.arg1); + local.arg1 = NULL; + } + free(temp_str); +} |