From 9ceebb2d93ec51da5fb045ba51cef9c362d37c5b Mon Sep 17 00:00:00 2001 From: pietru Date: Sun, 23 Feb 2025 19:51:25 +0100 Subject: [PATCH] add scripting --- gradle.properties | 2 +- .../net/pietru/cookie_utils/CookieUtils.java | 38 +--- .../cookie_utils/CookieUtilsLogicRunner.java | 31 ++++ .../pietru/cookie_utils/api/TextCommands.java | 18 +- .../mixins/BlockEntitySignMixin.java | 2 +- .../cookie_utils/mixins/LoginPacketMixin.java | 1 + .../mixins/PlayerPositionMixin.java | 34 +++- .../cookie_utils/scripting/BaseScript.java | 173 ++++++++++++++++++ .../scripting/ExecutionContext.java | 58 ++++++ .../cookie_utils/scripting/ScriptsDB.java | 56 ++++++ .../scripting/tokens/BaseToken.java | 13 ++ .../scripting/tokens/TokenEvent.java | 40 ++++ .../scripting/tokens/TokenMath.java | 80 ++++++++ .../scripting/tokens/TokenParticle.java | 172 +++++++++++++++++ .../scripting/tokens/TokenPlayer.java | 120 ++++++++++++ .../scripting/tokens/TokenRespawn.java | 48 +++++ .../scripting/tokens/TokenSet.java | 39 ++++ .../scripting/tokens/TokenSwitchZone.java | 60 ++++++ .../scripting/tokens/TokenTeleport.java | 77 ++++++++ .../cookie_utils/utils/player_utils.java | 1 + src/main/resources/cookie_utils.mixins.json | 8 +- 21 files changed, 1023 insertions(+), 48 deletions(-) create mode 100644 src/main/java/net/pietru/cookie_utils/CookieUtilsLogicRunner.java create mode 100644 src/main/java/net/pietru/cookie_utils/scripting/BaseScript.java create mode 100644 src/main/java/net/pietru/cookie_utils/scripting/ExecutionContext.java create mode 100644 src/main/java/net/pietru/cookie_utils/scripting/ScriptsDB.java create mode 100644 src/main/java/net/pietru/cookie_utils/scripting/tokens/BaseToken.java create mode 100644 src/main/java/net/pietru/cookie_utils/scripting/tokens/TokenEvent.java create mode 100644 src/main/java/net/pietru/cookie_utils/scripting/tokens/TokenMath.java create mode 100644 src/main/java/net/pietru/cookie_utils/scripting/tokens/TokenParticle.java create mode 100644 src/main/java/net/pietru/cookie_utils/scripting/tokens/TokenPlayer.java create mode 100644 src/main/java/net/pietru/cookie_utils/scripting/tokens/TokenRespawn.java create mode 100644 src/main/java/net/pietru/cookie_utils/scripting/tokens/TokenSet.java create mode 100644 src/main/java/net/pietru/cookie_utils/scripting/tokens/TokenSwitchZone.java create mode 100644 src/main/java/net/pietru/cookie_utils/scripting/tokens/TokenTeleport.java diff --git a/gradle.properties b/gradle.properties index ae04cb5..69f51d1 100644 --- a/gradle.properties +++ b/gradle.properties @@ -4,7 +4,7 @@ org.gradle.parallel=true org.gradle.caching=false # Project Info -version=1.0.6 +version=1.0.7 group=net.pietru id=cookie_utils diff --git a/src/main/java/net/pietru/cookie_utils/CookieUtils.java b/src/main/java/net/pietru/cookie_utils/CookieUtils.java index ab0f6ae..2bf4dbf 100644 --- a/src/main/java/net/pietru/cookie_utils/CookieUtils.java +++ b/src/main/java/net/pietru/cookie_utils/CookieUtils.java @@ -1,18 +1,13 @@ package net.pietru.cookie_utils; -import finalforeach.cosmicreach.GameSingletons; import dev.crmodders.cosmicquilt.api.entrypoint.ModInitializer; -import finalforeach.cosmicreach.world.Zone; +import finalforeach.cosmicreach.GameSingletons; import net.pietru.cookie_utils.api.Region; import net.pietru.cookie_utils.permissions.Permissions; +import net.pietru.cookie_utils.scripting.ScriptsDB; import net.pietru.cookie_utils.setups.setupCreator; import org.quiltmc.loader.api.ModContainer; -import java.io.IOException; -import java.util.*; - -import static net.pietru.cookie_utils.utils.prop.get_server_property_array; - public class CookieUtils implements ModInitializer { public static final String MOD_ID = "cookie_utils"; public static final String[] blocks = {}; @@ -26,35 +21,16 @@ public class CookieUtils implements ModInitializer { Permissions.reload_player_groups(true); System.out.println("CookieUtils loaded player groups..."); + ScriptsDB.reload_scripts(); + System.out.println("CookieUtils loaded scripts..."); + Region.reload_regions(); - System.out.println("CookieUtils loaded perm groups..."); + System.out.println("CookieUtils loaded regions..."); setupCreator.registerSetupCreators(); System.out.println("CookieUtils loaded setup creators..."); -// List paths = List.of(Gdx.files.internal(MOD_ID + "/assets.txt").readString().split("\n")); -// for (String path : paths){ -// if (path.contains("block_events")) { -// System.out.println("Loading " + path); -// BlockEvents.loadBlockEventsFromAsset(GameAssetLoader.loadAsset(path)); //Gdx.files.classpath(path) -// } -// } -// -// System.out.println("Registered CookieUtils Events"); -// -// -// System.out.println("Registered CookieUtils Entities"); -// -// for (String block:blocks) { -// System.out.println(block); -// try { -// Block.loadBlock(GameAssetLoader.loadAsset("cookie_utils:blocks/"+block+".json")); -// } catch (Exception var3) { -// throw new RuntimeException("Error parsing block: " + block, var3); -// } -// } -// -// System.out.println("Registered CookieUtils Blocks"); + GameSingletons.updateObservers.add(new CookieUtilsLogicRunner()); } } diff --git a/src/main/java/net/pietru/cookie_utils/CookieUtilsLogicRunner.java b/src/main/java/net/pietru/cookie_utils/CookieUtilsLogicRunner.java new file mode 100644 index 0000000..898bf9c --- /dev/null +++ b/src/main/java/net/pietru/cookie_utils/CookieUtilsLogicRunner.java @@ -0,0 +1,31 @@ +package net.pietru.cookie_utils; + +import finalforeach.cosmicreach.util.FloatConsumer; +import net.pietru.cookie_utils.api.Area; +import net.pietru.cookie_utils.api.Region; +import net.pietru.cookie_utils.scripting.ExecutionContext; +import net.pietru.cookie_utils.scripting.ScriptsDB; + +import java.util.Objects; + +public class CookieUtilsLogicRunner implements FloatConsumer { + float t = 0; + + @Override + public void accept(float v) { + t+=v; + if (t<1f) + return; + t=0; + for (Area area : Region.areas){ + if (!Objects.equals(area.scriptFile, "")){ + ExecutionContext context = new ExecutionContext(); + context.variable.put("delta",v); + + context.store_area_data(area); + + ScriptsDB.run_script(area.scriptFile,"on_area_update", context); + } + } + } +} diff --git a/src/main/java/net/pietru/cookie_utils/api/TextCommands.java b/src/main/java/net/pietru/cookie_utils/api/TextCommands.java index cd7cb42..c7271e2 100644 --- a/src/main/java/net/pietru/cookie_utils/api/TextCommands.java +++ b/src/main/java/net/pietru/cookie_utils/api/TextCommands.java @@ -14,7 +14,6 @@ import finalforeach.cosmicreach.entities.player.Player; import finalforeach.cosmicreach.io.SaveLocation; import finalforeach.cosmicreach.networking.NetworkIdentity; import finalforeach.cosmicreach.networking.packets.MessagePacket; -import finalforeach.cosmicreach.networking.packets.ParticleSystemPacket; import finalforeach.cosmicreach.networking.server.ServerSingletons; import finalforeach.cosmicreach.particles.GameParticleSystem; import finalforeach.cosmicreach.savelib.utils.TriConsumer; @@ -36,6 +35,7 @@ import java.util.*; import static net.pietru.cookie_utils.api.Region.*; import static net.pietru.cookie_utils.permissions.Permissions.has_perm; import static net.pietru.cookie_utils.permissions.Permissions.reload_perm_groups; +import static net.pietru.cookie_utils.scripting.ScriptsDB.reload_scripts; import static net.pietru.cookie_utils.utils.directory_utils.get_path_string; import static net.pietru.cookie_utils.utils.player_utils.get_player_id; import static net.pietru.cookie_utils.utils.player_utils.parseAsPlayer; @@ -368,23 +368,21 @@ public class TextCommands { packet.setupAndSend(channelHandlerContext); }); - commands.put("reload_groups",(args, networkIdentity, channelHandlerContext) -> { - MessagePacket packet = new MessagePacket("Reloaded groups..."); - reload_perm_groups(); - packet.setupAndSend(channelHandlerContext); - }); - commands.put("reload",(args, networkIdentity, channelHandlerContext) -> { List arg_list = Arrays.stream(args).toList(); String reloaded_funcs = ""; - if (arg_list.contains("regions") || args.length==1) { - reload_regions(); - reloaded_funcs+="regions "; + if (arg_list.contains("scripts") || args.length==1) { + reload_scripts(); + reloaded_funcs+="scripts "; } if (arg_list.contains("groups") || args.length==1) { reload_perm_groups(); reloaded_funcs+="groups "; } + if (arg_list.contains("regions") || args.length==1) { + reload_regions(); + reloaded_funcs+="regions "; + } MessagePacket packet = new MessagePacket("Reloaded: "+reloaded_funcs); packet.setupAndSend(channelHandlerContext); }); diff --git a/src/main/java/net/pietru/cookie_utils/mixins/BlockEntitySignMixin.java b/src/main/java/net/pietru/cookie_utils/mixins/BlockEntitySignMixin.java index dd69a8b..eb1b38d 100644 --- a/src/main/java/net/pietru/cookie_utils/mixins/BlockEntitySignMixin.java +++ b/src/main/java/net/pietru/cookie_utils/mixins/BlockEntitySignMixin.java @@ -46,7 +46,7 @@ public class BlockEntitySignMixin { boolean can_claim = true; for (int i = 0; (i< Region.areas.size && can_claim); i++){ Area a = Region.areas.get(i); - System.out.println(a.does_intersect(test)+"_"+a.name); + //System.out.println(a.does_intersect(test)+"_"+a.name); if (a.piority>=0 && a.does_intersect(test)) { can_claim=false; } diff --git a/src/main/java/net/pietru/cookie_utils/mixins/LoginPacketMixin.java b/src/main/java/net/pietru/cookie_utils/mixins/LoginPacketMixin.java index 0fec7bc..61ab3ae 100644 --- a/src/main/java/net/pietru/cookie_utils/mixins/LoginPacketMixin.java +++ b/src/main/java/net/pietru/cookie_utils/mixins/LoginPacketMixin.java @@ -23,6 +23,7 @@ public class LoginPacketMixin { private void event_player_data(CallbackInfo ci, @Local NetworkIdentity identity, @Local ChannelHandlerContext ctx){ if (is_plr_valid(account.getUniqueId())){ player_utils.usernames_to_ids.put(account.getUsername(), account.getUniqueId()); + player_utils.plr_last_area.put(account.getUniqueId(),""); } } } diff --git a/src/main/java/net/pietru/cookie_utils/mixins/PlayerPositionMixin.java b/src/main/java/net/pietru/cookie_utils/mixins/PlayerPositionMixin.java index 077021d..29f439e 100644 --- a/src/main/java/net/pietru/cookie_utils/mixins/PlayerPositionMixin.java +++ b/src/main/java/net/pietru/cookie_utils/mixins/PlayerPositionMixin.java @@ -11,13 +11,20 @@ import finalforeach.cosmicreach.networking.packets.MessagePacket; import finalforeach.cosmicreach.networking.packets.entities.PlayerPositionPacket; import finalforeach.cosmicreach.networking.server.ServerSingletons; import io.netty.channel.ChannelHandlerContext; +import net.pietru.cookie_utils.api.Area; +import net.pietru.cookie_utils.api.Region; import net.pietru.cookie_utils.permissions.Permissions; +import net.pietru.cookie_utils.scripting.ExecutionContext; +import net.pietru.cookie_utils.scripting.ScriptsDB; +import net.pietru.cookie_utils.utils.player_utils; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import java.util.Objects; + import static net.pietru.cookie_utils.api.Region.*; @Mixin(PlayerPositionPacket.class) @@ -37,10 +44,11 @@ public class PlayerPositionMixin { private void event_player_move(CallbackInfo ci, @Local NetworkIdentity identity, @Local ChannelHandlerContext ctx){ if (identity.getSide() != NetworkSide.CLIENT) { Account account = ServerSingletons.getAccount(identity); + Player player = ServerSingletons.getPlayer(identity); + if (!Permissions.has_user_special_perm(account.getUniqueId()) && !can_enter_position(position,"enter",playerUniqueId)) { ci.cancel(); - Player player = ServerSingletons.getPlayer(identity); Entity e = player.getEntity(); e.viewDirection.set(this.viewDir); e.viewPositionOffset.set(this.viewDirOff); @@ -58,6 +66,30 @@ public class PlayerPositionMixin { msg_packet.setupAndSend(ctx); if (!can_enter_position(plr_packet.position,"enter",playerUniqueId)) player.respawn(player.getZone()); + } else { + Area area = Region.get_area_at_pos(player.getPosition(), player.getZone()); + if (area!=null && !Objects.equals(player_utils.plr_last_area.getOrDefault(account.getUniqueId(), ""), area.name)) { + Area oldArea = Region.get_area(player_utils.plr_last_area.getOrDefault(account.getUniqueId(), "")); + player_utils.plr_last_area.put(account.getUniqueId(),area.name); + if (oldArea!=null) + if (!Objects.equals(oldArea.scriptFile, "")) { + ExecutionContext context = new ExecutionContext(); + + context.store_player_data(account); + context.store_area_data(oldArea); + + ScriptsDB.run_script(oldArea.scriptFile, "on_area_player_leave", context); + } + if (!Objects.equals(area.scriptFile, "")) { + ExecutionContext context = new ExecutionContext(); + + context.store_player_data(account); + context.store_area_data(area); + + ScriptsDB.run_script(area.scriptFile, "on_area_player_enter", context); + } + + } } } } diff --git a/src/main/java/net/pietru/cookie_utils/scripting/BaseScript.java b/src/main/java/net/pietru/cookie_utils/scripting/BaseScript.java new file mode 100644 index 0000000..646cbf1 --- /dev/null +++ b/src/main/java/net/pietru/cookie_utils/scripting/BaseScript.java @@ -0,0 +1,173 @@ +package net.pietru.cookie_utils.scripting; + +import net.pietru.cookie_utils.scripting.tokens.*; + +import java.io.File; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Scanner; + +public class BaseScript { + public static HashMap tokens = new HashMap<>(); + + + + static { + tokens.put("set", new TokenSet()); + tokens.put("event", new TokenEvent()); + tokens.put("respawn", new TokenRespawn()); + tokens.put("teleport", new TokenTeleport()); + tokens.put("switch-zone", new TokenSwitchZone()); + tokens.put("particle", new TokenParticle()); + tokens.put("player", new TokenPlayer()); + for (String key : TokenMath.valid_tokens) + tokens.put(key, new TokenMath()); + } + + + + + + + + public String name = ""; + public static HashMap> code_events = new HashMap<>(); + public static HashMap code_event_fails = new HashMap<>(); + + public void parse_file(File f) throws Exception{ + code_events.clear(); + code_event_fails.clear(); + Scanner scanner = new Scanner(f); + ArrayList temp_code_tokens = new ArrayList<>(); + while (scanner.hasNextLine()) { + String line = scanner.nextLine(); + if (line.startsWith("//")) + continue; + for (String t : List.of(line.split(" "))) + if (!t.isEmpty()) + temp_code_tokens.add(t); + temp_code_tokens.add("@parser_line_end_info_block"); + } + scanner.close(); + + int line_counter = 1; + String cur_event = ""; + String[] code_tokens = temp_code_tokens.toArray(new String[0]); + temp_code_tokens.clear(); + for (int i = 0; i < code_tokens.length;) { + if (code_tokens[i].equals("@parser_line_end_info_block")) { + line_counter++; + i++; + continue; + } + + if (code_tokens[i].equalsIgnoreCase("@EVENT") && code_tokens.length>=i+2) { + cur_event = code_tokens[i+1]; + if (!code_events.containsKey(cur_event)) { + code_events.put(cur_event, new ArrayList<>()); + } + i+=2; + continue; + } + if (cur_event.isEmpty()) + continue; + if (tokens.containsKey(code_tokens[i])){ + BaseToken baseToken = tokens.get(code_tokens[i]); + if (baseToken.canHandle(code_tokens,i)){ + int valid_tokens = baseToken.next_token(code_tokens,i); + for (int j = 0; j < valid_tokens; j++) { + if (code_tokens[i+j].equals("@parser_line_end_info_block")) { + line_counter++; + continue; + } + code_events.get(cur_event).add(code_tokens[i+j]); + } + i+=valid_tokens; + } else { + System.err.printf("[SCRIPTS] Script file \"%s\" failed to parse token \"%s\" at line %d with token %d.\n", name, code_tokens[i], line_counter,i+1); + } + } else { + System.err.printf("[SCRIPTS] Script file \"%s\" unknown token \"%s\" at line %d with token %d.\n", name, code_tokens[i],line_counter,i+1); + i++; + } + } + } + + public void handle(String event,ExecutionContext context){ + if (code_event_fails.getOrDefault(event,0)>=20) + return; + context.script=this; + + String[] code_tokens = new String[0]; + if (code_events.containsKey(event)) + code_tokens = code_events.get(event).toArray(new String[0]); + for (int i = 0; i < code_tokens.length;) { + if (tokens.containsKey(code_tokens[i])){ + BaseToken baseToken = tokens.get(code_tokens[i]); + if (baseToken.handle(code_tokens,i,context)){ + i+=baseToken.next_token(code_tokens,i); + } else { + System.err.printf("[SCRIPTS] Script file \"%s\" failed to handle token \"%s\" of event %s at token %d.\n", name, code_tokens[i], event,i+1); + code_event_fails.put(event,code_event_fails.getOrDefault(event,0)+1); + i++; + } + } else { + System.err.printf("[SCRIPTS] Script file \"%s\" unknown token \"%s\" at line %s with token %d.\n", name, code_tokens[i], event,i+1); + code_event_fails.put(event,code_event_fails.getOrDefault(event,0)+1); + i++; + } + } + } + + public static void log_token_error(BaseToken token, String msg){ + System.err.printf("[SCRIPTS][%s] %s\n", token.get_token_checker_id(),msg); + } + + public static ArrayList get_string(String[] tokens, int step){ + ArrayList text = new ArrayList<>(); + if (tokens[step].startsWith("\"")) { + text.add(tokens[step]); + for (int i = step + 1; i < tokens.length; i++) { + if (tokens[i].endsWith("\"")){ + text.add(tokens[i].substring(0,tokens[i].length()-1)); + break; + } else { + text.add(tokens[step]); + } + } + } + else if (tokens[step].startsWith("'")) { + text.add(tokens[step].substring(1)); + for (int i = step + 1; i < tokens.length; i++) { + if (tokens[i].endsWith("'")) { + text.add(tokens[i].substring(0,tokens[i].length()-1)); + break; + } else { + text.add(tokens[step]); + } + } + } else { + text.add(tokens[step]); + } + return text; + } + + public static String get_if_variable(String token,ExecutionContext context){ + if (token.startsWith("#")) + return String.valueOf(context.variable.get(token.substring(1))); + return token; + } + + public static HashMap get_optional_args(String[] tokens, int step, List valid_args){ + HashMap optional_args = new HashMap<>(); + + for (int i = step; i < tokens.length-1; i+=2) { + if (!valid_args.contains(tokens[i])){ + break; + } + optional_args.put(tokens[i],tokens[i+1]); + } + return optional_args; + } +} diff --git a/src/main/java/net/pietru/cookie_utils/scripting/ExecutionContext.java b/src/main/java/net/pietru/cookie_utils/scripting/ExecutionContext.java new file mode 100644 index 0000000..435af35 --- /dev/null +++ b/src/main/java/net/pietru/cookie_utils/scripting/ExecutionContext.java @@ -0,0 +1,58 @@ +package net.pietru.cookie_utils.scripting; + +import com.badlogic.gdx.math.Vector3; +import finalforeach.cosmicreach.accounts.Account; +import finalforeach.cosmicreach.entities.player.Player; +import net.pietru.cookie_utils.api.Area; + +import java.util.HashMap; +import java.util.Map; + +public class ExecutionContext { + public BaseScript script; + public Map variable = new HashMap<>(); + + public void store_player_data(Account account){ + variable.put("event_player_id", account.getUniqueId()); + Player player = account.getPlayer(); + Vector3 pos = player.getPosition(); + variable.put("event_player_pos_x", pos.x); + variable.put("event_player_pos_y", pos.y); + variable.put("event_player_pos_z", pos.z); + + variable.put("event_player_zone", player.zoneId); + variable.put("event_player_zoneId", player.zoneId); + + variable.put("event_player_gamemode", player.gamemode.gamemodeId); + variable.put("event_player_gamemodeId", player.gamemode.gamemodeId); + variable.put("event_player_gamemode_short", player.gamemode.shortId); + variable.put("event_player_gamemode_shortId", player.gamemode.shortId); + + variable.put("event_player_loading", player.loading); + + variable.put("event_player_is_prone", player.isProne); + variable.put("event_player_is_sprinting", player.isSprinting); + variable.put("event_player_is_dead", player.isSprinting); + } + + public void store_area_data(Area area){ + variable.put("area_name",area.name); + variable.put("area_zone",area.zoneId); + variable.put("area_zoneId",area.zoneId); + variable.put("area_parent",area.parent); + variable.put("area_enabled",area.enabled); + variable.put("area_protect",area.protect); + + variable.put("area_center_x",area.getBox().getCenterX()); + variable.put("area_center_y",area.getBox().getCenterY()); + variable.put("area_center_z",area.getBox().getCenterZ()); + + variable.put("area_min_x",area.getBox().min.x); + variable.put("area_min_y",area.getBox().min.y); + variable.put("area_min_z",area.getBox().min.z); + + variable.put("area_max_x",area.getBox().max.x); + variable.put("area_max_y",area.getBox().max.y); + variable.put("area_max_z",area.getBox().max.z); + } +} diff --git a/src/main/java/net/pietru/cookie_utils/scripting/ScriptsDB.java b/src/main/java/net/pietru/cookie_utils/scripting/ScriptsDB.java new file mode 100644 index 0000000..2f02315 --- /dev/null +++ b/src/main/java/net/pietru/cookie_utils/scripting/ScriptsDB.java @@ -0,0 +1,56 @@ +package net.pietru.cookie_utils.scripting; + +import finalforeach.cosmicreach.io.SaveLocation; +import net.pietru.cookie_utils.utils.directory_utils; + +import java.io.File; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; + +public class ScriptsDB { + public static Map scripts_storage = new HashMap<>(); + + public static void run_script(String script,String event,ExecutionContext context){ + if (scripts_storage.containsKey(script)) + scripts_storage.get(script).handle(event,context); + } + + + public static boolean is_not_reloading = true; + + public static void reload_scripts() { + is_not_reloading = false; + + scripts_storage.clear(); + + File scripts_folder = new File(SaveLocation.getSaveFolder(), "scripts"); + if (!scripts_folder.exists()) + scripts_folder.mkdirs(); + ArrayList scripts = directory_utils.list_files_in_dir_recursive(scripts_folder,((dir, name) -> name.endsWith(".ck"))); + + System.out.println("[SCRIPTS] Trying to load %s scripts.".replace("%s", String.valueOf(scripts.size()))); + for (File f : scripts) { + BaseScript script = new BaseScript(); + + script.name = f.getPath().replace(scripts_folder.getPath(), "").replace("\\", "/"); + if (script.name.startsWith("/")) + script.name= script.name.substring(1); + + try { + script.parse_file(f); + } catch (Exception ignored) { + System.err.println("[SCRIPTS] Script file \"%s\" had encountered exception while loading...".replace("%s", f.getPath())); + continue; + } + + scripts_storage.put(script.name, script); + + System.out.println("[SCRIPTS] Loaded script file \"%s\"".replace("%s", script.name)); + } + + is_not_reloading = true; + + System.out.println("[SCRIPTS] Loaded %s scripts.".replace("%s", String.valueOf(scripts_storage.size()))); + } +} \ No newline at end of file diff --git a/src/main/java/net/pietru/cookie_utils/scripting/tokens/BaseToken.java b/src/main/java/net/pietru/cookie_utils/scripting/tokens/BaseToken.java new file mode 100644 index 0000000..ff4088c --- /dev/null +++ b/src/main/java/net/pietru/cookie_utils/scripting/tokens/BaseToken.java @@ -0,0 +1,13 @@ +package net.pietru.cookie_utils.scripting.tokens; + +import net.pietru.cookie_utils.scripting.ExecutionContext; + +public interface BaseToken { + String get_token_checker_id(); + + boolean canHandle(String[] tokens, int step); + + int next_token(String[] tokens, int step); + + boolean handle(String[] tokens, int step, ExecutionContext executionContext); +} diff --git a/src/main/java/net/pietru/cookie_utils/scripting/tokens/TokenEvent.java b/src/main/java/net/pietru/cookie_utils/scripting/tokens/TokenEvent.java new file mode 100644 index 0000000..8f9a87a --- /dev/null +++ b/src/main/java/net/pietru/cookie_utils/scripting/tokens/TokenEvent.java @@ -0,0 +1,40 @@ +package net.pietru.cookie_utils.scripting.tokens; + +import net.pietru.cookie_utils.scripting.BaseScript; +import net.pietru.cookie_utils.scripting.ExecutionContext; + +public class TokenEvent implements BaseToken { + + @Override + public String get_token_checker_id() { + return "token_event"; + } + + /** + * token_name + * event_name + * */ + @Override + public boolean canHandle(String[] tokens, int step) { + String token = tokens[step]; + return token.equals("event") && tokens.length>=step+2; + } + + @Override + public int next_token(String[] tokens, int step) { + return 2; + } + + @Override + public boolean handle(String[] tokens, int step, ExecutionContext executionContext) { + String token = tokens[step]; + if (!token.equals("set")) + return false; + + String event = (String) BaseScript.get_if_variable(tokens[step+1],executionContext); + + executionContext.script.handle(event,executionContext); + + return true; + } +} diff --git a/src/main/java/net/pietru/cookie_utils/scripting/tokens/TokenMath.java b/src/main/java/net/pietru/cookie_utils/scripting/tokens/TokenMath.java new file mode 100644 index 0000000..3c5ec9a --- /dev/null +++ b/src/main/java/net/pietru/cookie_utils/scripting/tokens/TokenMath.java @@ -0,0 +1,80 @@ +package net.pietru.cookie_utils.scripting.tokens; + +import net.pietru.cookie_utils.scripting.BaseScript; +import net.pietru.cookie_utils.scripting.ExecutionContext; + +import java.util.List; + +public class TokenMath implements BaseToken { + + public static final List valid_tokens = List.of( + "add", + "sub", + "mul", + "dev" + ); + + + @Override + public String get_token_checker_id() { + return "token_player"; + } + + @Override + public boolean canHandle(String[] tokens, int step) { + String token = tokens[step]; + return valid_tokens.contains(token) && tokens.length>=step+4; + } + + /** + * token_name + * a + * b + * store_var_name + * */ + @Override + public int next_token(String[] tokens, int step) { + return 4; + } + + @Override + public boolean handle(String[] tokens, int step, ExecutionContext executionContext) { + String token = tokens[step]; + if (!valid_tokens.contains(token)) + return false; + + float a,b,c; + try { + a = Float.parseFloat(BaseScript.get_if_variable(tokens[step+1],executionContext)); + } catch (Exception e) { + BaseScript.log_token_error(this,"Failed to parse arg a."); + return false; + } + try { + b = Float.parseFloat(BaseScript.get_if_variable(tokens[step+2],executionContext)); + if (b==0 && token.equalsIgnoreCase("dev")){ + BaseScript.log_token_error(this,"Arg b can't be 0."); + return false; + } + + } catch (Exception e) { + BaseScript.log_token_error(this,"Failed to parse arg b."); + return false; + } + + c = switch (token){ + case "add" -> a+b; + case "sub" -> a-b; + case "mul" -> a*b; + case "dev" -> a/b; + default -> 0; + }; + + String key = BaseScript.get_if_variable(tokens[step+3],executionContext); + + executionContext.variable.put(key,c); + + + return true; + } +} diff --git a/src/main/java/net/pietru/cookie_utils/scripting/tokens/TokenParticle.java b/src/main/java/net/pietru/cookie_utils/scripting/tokens/TokenParticle.java new file mode 100644 index 0000000..232f760 --- /dev/null +++ b/src/main/java/net/pietru/cookie_utils/scripting/tokens/TokenParticle.java @@ -0,0 +1,172 @@ +package net.pietru.cookie_utils.scripting.tokens; + +import com.badlogic.gdx.graphics.Color; +import finalforeach.cosmicreach.GameSingletons; +import finalforeach.cosmicreach.entities.player.Player; +import finalforeach.cosmicreach.networking.packets.ParticleSystemPacket; +import finalforeach.cosmicreach.networking.server.ServerSingletons; +import finalforeach.cosmicreach.particles.GameParticleSystem; +import finalforeach.cosmicreach.particles.IParticleComponent; +import finalforeach.cosmicreach.particles.spawn.GameParticleSpawnSphere; +import finalforeach.cosmicreach.world.Zone; +import net.pietru.cookie_utils.scripting.BaseScript; +import net.pietru.cookie_utils.scripting.ExecutionContext; +import net.pietru.cookie_utils.utils.ParticleUtil; + +import java.util.List; +import java.util.Map; + +import static net.pietru.cookie_utils.utils.player_utils.parseAsPlayer; + +public class TokenParticle implements BaseToken { + + public static final List optional_args = List.of( + "color", + "duration", + "max_particles", + "size", + "max_age", + "min_radius", + "max_radius", + "player" + ); + + + @Override + public String get_token_checker_id() { + return "token_particle"; + } + + @Override + public boolean canHandle(String[] tokens, int step) { + String token = tokens[step]; + return token.equals("particle") && tokens.length>=step+5+BaseScript.get_optional_args( + tokens, + step+5, + optional_args + ).size()*2; + } + + /** + * token_name + * zone + * x + * y + * z + * */ + @Override + public int next_token(String[] tokens, int step) { + return 5+BaseScript.get_optional_args( + tokens, + step+5, + optional_args + ).size()*2; + } + + @Override + public boolean handle(String[] tokens, int step, ExecutionContext executionContext) { + String token = tokens[step]; + if (!token.equals("particle")) + return false; + + String zoneId = BaseScript.get_if_variable(tokens[step+1],executionContext); + Zone zone = GameSingletons.world.getZoneIfExists(zoneId); + + float x,y,z; + try { + x = Float.parseFloat(BaseScript.get_if_variable(tokens[step+2],executionContext)); + } catch (Exception e) { + BaseScript.log_token_error(this,"Failed to parse x cordinate."); + return false; + } + try { + y = Float.parseFloat(BaseScript.get_if_variable(tokens[step+3],executionContext)); + } catch (Exception e) { + BaseScript.log_token_error(this,"Failed to parse y cordinate."); + return false; + } + try { + z = Float.parseFloat(BaseScript.get_if_variable(tokens[step+4],executionContext)); + } catch (Exception e) { + BaseScript.log_token_error(this,"Failed to parse z cordinate."); + return false; + } + + Map args = BaseScript.get_optional_args( + tokens, + step+5, + optional_args + ); + GameParticleSystem system = GameParticleSystem.laserParticleSystem.copy(); + + String color_key = args.getOrDefault("color","SKY"); + Color c; + switch (color_key.toLowerCase()){ + case "light_gray" -> c = Color.LIGHT_GRAY; + case "gray" -> c = Color.GRAY; + case "dark_gray" -> c = Color.DARK_GRAY; + case "black" -> c = Color.BLACK; + case "blue" -> c = Color.BLUE; + case "navy" -> c = Color.NAVY; + case "royal" -> c = Color.ROYAL; + case "slate" -> c = Color.SLATE; + case "sky" -> c = Color.SKY; + case "cyan" -> c = Color.CYAN; + case "teal" -> c = Color.TEAL; + case "green" -> c = Color.GREEN; + case "chartreuse" -> c = Color.CHARTREUSE; + case "lime" -> c = Color.LIME; + case "forest" -> c = Color.FOREST; + case "olive" -> c = Color.OLIVE; + case "yellow" -> c = Color.YELLOW; + case "gold" -> c = Color.GOLD; + case "goldenrod" -> c = Color.GOLDENROD; + case "orange" -> c = Color.ORANGE; + case "brown" -> c = Color.BROWN; + case "tan" -> c = Color.TAN; + case "firebrick" -> c = Color.FIREBRICK; + case "red" -> c = Color.RED; + case "scarlet" -> c = Color.SCARLET; + case "coral" -> c = Color.CORAL; + case "salmon" -> c = Color.SALMON; + case "pink" -> c = Color.PINK; + case "magenta" -> c = Color.MAGENTA; + case "purple" -> c = Color.PURPLE; + case "violet" -> c = Color.VIOLET; + case "maroon" -> c = Color.MAROON; + default -> c = Color.LIGHT_GRAY; + } + if (color_key.startsWith("#")) + Color.valueOf(color_key,c); + system.startColor.set(c); + + system.duration = Float.parseFloat(args.getOrDefault("duration","1")); + system.maxParticles = Integer.parseInt(args.getOrDefault("max_particles","1")); + system.startSize = Float.parseFloat(args.getOrDefault("size",".2")); + system.maxAge = Float.parseFloat(args.getOrDefault("max_age","1")); + + Player player = parseAsPlayer(BaseScript.get_if_variable(args.getOrDefault("player",""),executionContext)); + + for (IParticleComponent component : system.particleComponents){ + if (component instanceof GameParticleSpawnSphere) + ((GameParticleSpawnSphere) component).setRadius( + Float.parseFloat(args.getOrDefault("min_radius","0")), + Float.parseFloat(args.getOrDefault("max_radius","0")) + ); + } + + + if (player!=null) + ParticleUtil.send_particle(x,y,z,system,ServerSingletons.getConnection(player).ctx); + else { + system.setOrigin(x,y,z); + if (zone != null) + ServerSingletons.SERVER.broadcast(zone, new ParticleSystemPacket(system)); + else + for (Zone wz : GameSingletons.world.getZones()) + ServerSingletons.SERVER.broadcast(wz, new ParticleSystemPacket(system)); + } + + return true; + } +} diff --git a/src/main/java/net/pietru/cookie_utils/scripting/tokens/TokenPlayer.java b/src/main/java/net/pietru/cookie_utils/scripting/tokens/TokenPlayer.java new file mode 100644 index 0000000..16c3a21 --- /dev/null +++ b/src/main/java/net/pietru/cookie_utils/scripting/tokens/TokenPlayer.java @@ -0,0 +1,120 @@ +package net.pietru.cookie_utils.scripting.tokens; + +import com.badlogic.gdx.graphics.Color; +import finalforeach.cosmicreach.GameSingletons; +import finalforeach.cosmicreach.entities.player.Player; +import finalforeach.cosmicreach.networking.packets.ParticleSystemPacket; +import finalforeach.cosmicreach.networking.packets.entities.MaxHPEntityPacket; +import finalforeach.cosmicreach.networking.packets.entities.PlayerPositionPacket; +import finalforeach.cosmicreach.networking.server.ServerIdentity; +import finalforeach.cosmicreach.networking.server.ServerSingletons; +import finalforeach.cosmicreach.particles.GameParticleSystem; +import finalforeach.cosmicreach.particles.IParticleComponent; +import finalforeach.cosmicreach.particles.spawn.GameParticleSpawnSphere; +import finalforeach.cosmicreach.world.Zone; +import net.pietru.cookie_utils.scripting.BaseScript; +import net.pietru.cookie_utils.scripting.ExecutionContext; +import net.pietru.cookie_utils.utils.ParticleUtil; + +import java.util.List; +import java.util.Map; + +import static net.pietru.cookie_utils.utils.player_utils.parseAsPlayer; + +public class TokenPlayer implements BaseToken { + + public static final List optional_args = List.of( + "velocity_x", + "velocity_y", + "velocity_z", + "max_health" + ); + + + @Override + public String get_token_checker_id() { + return "token_player"; + } + + @Override + public boolean canHandle(String[] tokens, int step) { + String token = tokens[step]; + return token.equals("player") && tokens.length>=step+2+BaseScript.get_optional_args( + tokens, + step, + optional_args + ).size()*2; + } + + /** + * token_name + * player_var + * */ + @Override + public int next_token(String[] tokens, int step) { + return 2+BaseScript.get_optional_args( + tokens, + step+2, + optional_args + ).size()*2; + } + + @Override + public boolean handle(String[] tokens, int step, ExecutionContext executionContext) { + String token = tokens[step]; + if (!token.equals("player")) + return false; + + Player player = parseAsPlayer(BaseScript.get_if_variable(tokens[step+1],executionContext)); + if (player==null) { + BaseScript.log_token_error(this, "Failed to parse player."); + return false; + } + + ServerIdentity identity = ServerSingletons.getConnection(player); + + Map args = BaseScript.get_optional_args( + tokens, + step+2, + optional_args + ); + if (args.containsKey("velocity_x")) + try { + player.getEntity().velocity.x=Float.parseFloat(BaseScript.get_if_variable(args.get("velocity_x"),executionContext)); + } catch (Exception e) { + BaseScript.log_token_error(this,"Failed to parse velocity x."); + return false; + } + + if (args.containsKey("velocity_y")) + try { + player.getEntity().velocity.y=Float.parseFloat(BaseScript.get_if_variable(args.get("velocity_y"),executionContext)); + } catch (Exception e) { + BaseScript.log_token_error(this,"Failed to parse velocity y."); + return false; + } + + if (args.containsKey("velocity_z")) + try { + player.getEntity().velocity.z=Float.parseFloat(BaseScript.get_if_variable(args.get("velocity_z"),executionContext)); + } catch (Exception e) { + BaseScript.log_token_error(this,"Failed to parse velocity z."); + return false; + } + + if (args.containsKey("max_health")) + try { + player.getEntity().maxHitpoints=Float.parseFloat(BaseScript.get_if_variable(args.get("max_health"),executionContext)); + MaxHPEntityPacket packet = new MaxHPEntityPacket(player.getEntity()); + packet.setupAndSend(identity); + } catch (Exception e) { + BaseScript.log_token_error(this,"Failed to parse max health."); + return false; + } + + + + + return true; + } +} diff --git a/src/main/java/net/pietru/cookie_utils/scripting/tokens/TokenRespawn.java b/src/main/java/net/pietru/cookie_utils/scripting/tokens/TokenRespawn.java new file mode 100644 index 0000000..1b85e91 --- /dev/null +++ b/src/main/java/net/pietru/cookie_utils/scripting/tokens/TokenRespawn.java @@ -0,0 +1,48 @@ +package net.pietru.cookie_utils.scripting.tokens; + +import finalforeach.cosmicreach.GameSingletons; +import finalforeach.cosmicreach.entities.player.Player; +import finalforeach.cosmicreach.world.Zone; +import net.pietru.cookie_utils.scripting.BaseScript; +import net.pietru.cookie_utils.scripting.ExecutionContext; + +import static net.pietru.cookie_utils.utils.player_utils.parseAsPlayer; + +public class TokenRespawn implements BaseToken { + + @Override + public String get_token_checker_id() { + return "token_respawn"; + } + + @Override + public boolean canHandle(String[] tokens, int step) { + String token = tokens[step]; + return token.equals("respawn") && tokens.length>=step+2; + } + + /** + * token_name + * player_var + * */ + @Override + public int next_token(String[] tokens, int step) { + return 2; + } + + @Override + public boolean handle(String[] tokens, int step, ExecutionContext executionContext) { + String token = tokens[step]; + if (!token.equals("respawn")) + return false; + + Player player = parseAsPlayer(BaseScript.get_if_variable(tokens[step+1],executionContext)); + if (player==null) + return false; + + Zone zone = player.getZone(); + player.respawn(zone); + + return true; + } +} diff --git a/src/main/java/net/pietru/cookie_utils/scripting/tokens/TokenSet.java b/src/main/java/net/pietru/cookie_utils/scripting/tokens/TokenSet.java new file mode 100644 index 0000000..aebf332 --- /dev/null +++ b/src/main/java/net/pietru/cookie_utils/scripting/tokens/TokenSet.java @@ -0,0 +1,39 @@ +package net.pietru.cookie_utils.scripting.tokens; + +import net.pietru.cookie_utils.scripting.BaseScript; +import net.pietru.cookie_utils.scripting.ExecutionContext; + +import java.util.ArrayList; + +public class TokenSet implements BaseToken { + + @Override + public String get_token_checker_id() { + return "token_set"; + } + + @Override + public boolean canHandle(String[] tokens, int step) { + String token = tokens[step]; + return token.equals("set") && tokens.length>=step+3; + } + + @Override + public int next_token(String[] tokens, int step) { + return 2+BaseScript.get_string(tokens, step+2).size(); + } + + @Override + public boolean handle(String[] tokens, int step, ExecutionContext executionContext) { + String token = tokens[step]; + if (!token.equals("set")) + return false; + + String key = BaseScript.get_if_variable(tokens[step+1],executionContext); + String val = String.join(" ", BaseScript.get_string(tokens, step+2)); + + executionContext.variable.put(key,val); + + return true; + } +} diff --git a/src/main/java/net/pietru/cookie_utils/scripting/tokens/TokenSwitchZone.java b/src/main/java/net/pietru/cookie_utils/scripting/tokens/TokenSwitchZone.java new file mode 100644 index 0000000..f626360 --- /dev/null +++ b/src/main/java/net/pietru/cookie_utils/scripting/tokens/TokenSwitchZone.java @@ -0,0 +1,60 @@ +package net.pietru.cookie_utils.scripting.tokens; + +import finalforeach.cosmicreach.GameSingletons; +import finalforeach.cosmicreach.entities.player.Player; +import finalforeach.cosmicreach.world.Zone; +import net.pietru.cookie_utils.scripting.BaseScript; +import net.pietru.cookie_utils.scripting.ExecutionContext; + +import static net.pietru.cookie_utils.permissions.Permissions.has_perm; +import static net.pietru.cookie_utils.utils.player_utils.parseAsPlayer; + +public class TokenSwitchZone implements BaseToken { + + @Override + public String get_token_checker_id() { + return "token_switch_zone"; + } + + @Override + public boolean canHandle(String[] tokens, int step) { + String token = tokens[step]; + return token.equals("switch-zone") && tokens.length>=step+3; + } + + /** + * token_name + * player_var + * zone_id + * */ + @Override + public int next_token(String[] tokens, int step) { + return 3; + } + + @Override + public boolean handle(String[] tokens, int step, ExecutionContext executionContext) { + String token = tokens[step]; + if (!token.equals("switch-zone")) + return false; + + Player player = parseAsPlayer(BaseScript.get_if_variable(tokens[step+1],executionContext)); + if (player==null) + return false; + + String zoneId = BaseScript.get_if_variable(tokens[step+2],executionContext); + Zone zone = GameSingletons.world.getZoneIfExists(zoneId); + if (zone==null) + return false; + + Zone old = player.getZone(); + if (!old.zoneId.equals(zoneId)) { + zone.addPlayer(player); + player.setZone(zoneId); + player.respawn(zone); + old.removePlayer(player); + } + + return true; + } +} diff --git a/src/main/java/net/pietru/cookie_utils/scripting/tokens/TokenTeleport.java b/src/main/java/net/pietru/cookie_utils/scripting/tokens/TokenTeleport.java new file mode 100644 index 0000000..7630c84 --- /dev/null +++ b/src/main/java/net/pietru/cookie_utils/scripting/tokens/TokenTeleport.java @@ -0,0 +1,77 @@ +package net.pietru.cookie_utils.scripting.tokens; + +import com.badlogic.gdx.math.Vector3; +import finalforeach.cosmicreach.GameSingletons; +import finalforeach.cosmicreach.entities.player.Player; +import finalforeach.cosmicreach.networking.packets.entities.PlayerPositionPacket; +import finalforeach.cosmicreach.networking.server.ServerSingletons; +import finalforeach.cosmicreach.world.Zone; +import net.pietru.cookie_utils.scripting.BaseScript; +import net.pietru.cookie_utils.scripting.ExecutionContext; + +import static net.pietru.cookie_utils.permissions.Permissions.has_perm; +import static net.pietru.cookie_utils.utils.player_utils.parseAsPlayer; + +public class TokenTeleport implements BaseToken { + + @Override + public String get_token_checker_id() { + return "token_teleport"; + } + + @Override + public boolean canHandle(String[] tokens, int step) { + String token = tokens[step]; + return token.equals("teleport") && tokens.length>=step+5; + } + + /** + * token_name + * player_var + * x + * y + * z + * */ + @Override + public int next_token(String[] tokens, int step) { + return 5; + } + + @Override + public boolean handle(String[] tokens, int step, ExecutionContext executionContext) { + String token = tokens[step]; + if (!token.equals("teleport")) + return false; + + Player player = parseAsPlayer(BaseScript.get_if_variable(tokens[step+1],executionContext)); + if (player==null) + return false; + + float x,y,z; + try { + x = Float.parseFloat(BaseScript.get_if_variable(tokens[step+2],executionContext)); + } catch (Exception e) { + BaseScript.log_token_error(this,"Failed to parse x cordinate."); + return false; + } + try { + y = Float.parseFloat(BaseScript.get_if_variable(tokens[step+3],executionContext)); + } catch (Exception e) { + BaseScript.log_token_error(this,"Failed to parse y cordinate."); + return false; + } + try { + z = Float.parseFloat(BaseScript.get_if_variable(tokens[step+4],executionContext)); + } catch (Exception e) { + BaseScript.log_token_error(this,"Failed to parse z cordinate."); + return false; + } + + player.getEntity().setPosition(new Vector3(x,y,z)); + + PlayerPositionPacket plr_packet = new PlayerPositionPacket(player); + plr_packet.setupAndSend(ServerSingletons.getConnection(player)); + + return true; + } +} diff --git a/src/main/java/net/pietru/cookie_utils/utils/player_utils.java b/src/main/java/net/pietru/cookie_utils/utils/player_utils.java index f3749a6..03d089a 100644 --- a/src/main/java/net/pietru/cookie_utils/utils/player_utils.java +++ b/src/main/java/net/pietru/cookie_utils/utils/player_utils.java @@ -15,6 +15,7 @@ import java.util.Map; public class player_utils { public static Map usernames_to_ids = new HashMap<>(); + public static Map plr_last_area = new HashMap<>(); public static boolean has_player(String value){ return usernames_to_ids.containsKey(value) || usernames_to_ids.containsValue(value); diff --git a/src/main/resources/cookie_utils.mixins.json b/src/main/resources/cookie_utils.mixins.json index c5fbd01..ebba0e2 100644 --- a/src/main/resources/cookie_utils.mixins.json +++ b/src/main/resources/cookie_utils.mixins.json @@ -6,16 +6,16 @@ "mixins": [ "BlockActionExplodeMixin", "BlockBreakMixin", + "BlockEntitySignMixin", "BlockPlaceMixin", "InteractBlockMixin", "LoginPacketMixin", "MessagePacketMixin", "MobSpawnerMixin", - "PlayerPositionMixin", "NettyServerMixin", - "ServerSingletonsMixin", - "BlockEntitySignMixin", - "PlayerEntityMixin" + "PlayerEntityMixin", + "PlayerPositionMixin", + "ServerSingletonsMixin" ], "client": [], "injectors": {