Merge branch 'dev' into syntax-highlighter-unified

This commit is contained in:
Kam committed 2026-03-02 16:38:44 -05:00
commit c16aae75e2
16 files changed
+184 -52

No files matched your search

+1 -1
Submodule src/api updated: 22135344e8...9fbd1eceff.
@@ -136,13 +136,13 @@ public class CommandKamkeel extends CommandBase {
List<String> keys = new ArrayList<>(RequirementCheckerRegistry.getAllKeys());
return CommandBase.getListOfStringsMatchingLastWord(args, keys.toArray(new String[keys.size()]));
} else if (usage.equals("<effectName>")) {
List<String> keys = getSortedEffectNames();
List<String> keys = stripColorCodes(getSortedEffectNames());
return CommandBase.getListOfStringsMatchingLastWord(args, keys.toArray(new String[keys.size()]));
} else if (usage.equals("<ability>")) {
List<String> keys = getPlayerAbilityNames();
List<String> keys = stripColorCodes(getPlayerAbilityNames());
return CommandBase.getListOfStringsMatchingLastWord(args, keys.toArray(new String[keys.size()]));
} else if (usage.equals("<chain>")) {
List<String> keys = getPlayerChainNames();
List<String> keys = stripColorCodes(getPlayerChainNames());
return CommandBase.getListOfStringsMatchingLastWord(args, keys.toArray(new String[keys.size()]));
}
}
@@ -150,6 +150,14 @@ public class CommandKamkeel extends CommandBase {
return command.addTabCompletionOptions(sender, Arrays.copyOfRange(args, 1, args.length));
}
private static List<String> stripColorCodes(List<String> list) {
List<String> result = new ArrayList<>(list.size());
for (String s : list) {
result.add(s.replaceAll("\u00A7[0-9a-fk-or]", ""));
}
return result;
}
public CommandKamkeelBase getCommand(String[] args) {
if (args.length == 0)
return null;
@@ -308,6 +308,7 @@ public class EffectCommand extends CommandKamkeelBase {
// Helper method to find effects by name.
private List<EffectEntry> findEffectsByName(String name) {
String strippedName = stripColorCodes(name);
List<EffectEntry> matches = new ArrayList<>();
CustomEffectController controller = CustomEffectController.getInstance();
for (Map.Entry<Integer, HashMap<Integer, CustomEffect>> entry : controller.indexMapper.entrySet()) {
@@ -317,11 +318,12 @@ public class EffectCommand extends CommandKamkeelBase {
for (Map.Entry<Integer, CustomEffect> effectEntry : effects.entrySet()) {
int id = effectEntry.getKey();
CustomEffect effect = effectEntry.getValue();
if (effect.getName().equalsIgnoreCase(name)) {
String effectName = stripColorCodes(effect.getName());
if (effectName.equalsIgnoreCase(strippedName)) {
List<EffectEntry> exact = new ArrayList<>();
exact.add(new EffectEntry(idx, id, effect));
return exact;
} else if (effect.getName().toLowerCase().contains(name.toLowerCase())) {
} else if (effectName.toLowerCase().contains(strippedName.toLowerCase())) {
matches.add(new EffectEntry(idx, id, effect));
}
}
@@ -329,6 +331,10 @@ public class EffectCommand extends CommandKamkeelBase {
return matches;
}
private static String stripColorCodes(String s) {
return s.replaceAll("\u00A7[0-9a-fk-or]", "");
}
public static List<String> getSortedEffectNames() {
List<EffectEntry> entries = new ArrayList<>();
CustomEffectController controller = CustomEffectController.getInstance();
@@ -167,7 +167,9 @@ public class GuiScript extends GuiScriptInterface {
container == null ? "" : container.script);
}
activeArea.setLanguage(script.getLanguage());
// Use the container's language for syntax highlighting, fall back to handler default
String language = (container != null) ? container.getLanguage() : script.getLanguage();
activeArea.setLanguage(language);
activeArea.setScriptContext(getScriptContext());
// Set editor globals based on the active NPC hook
@@ -224,16 +226,19 @@ public class GuiScript extends GuiScriptInterface {
addButton(new GuiNpcButton(105, guiLeft + 60, guiTop + 4, 80, 20,
consoleOptions.toArray(new String[0]), activeConsole));
addLabel(new GuiNpcLabel(1, "script.language", guiLeft + 232, guiTop + 30));
addLabel(new GuiNpcLabel(1, "script.default", guiLeft + 232, guiTop + 30));
List<String> languageOptions = getLanguageOptions();
addButton(new GuiNpcButton(103, guiLeft + 294, guiTop + 25, 80, 20,
languageOptions.toArray(new String[0]), getLanguageIndex(languageOptions)));
getButton(103).enabled = languageOptions.size() > 0;
addLabel(new GuiNpcLabel(2, "gui.enabled", guiLeft + 232, guiTop + 53));
addButton(new GuiNpcButton(104, guiLeft + 294, guiTop + 48, 50, 20,
new String[]{"gui.no", "gui.yes"}, script.enabled ? 1 : 0));
// Disable language/enabled controls until server data actually arrives
getButton(103).enabled = serverDataReceived && languageOptions.size() > 0;
getButton(104).enabled = serverDataReceived;
if (MinecraftServer.getServer() != null)
addButton(new GuiNpcButton(106, guiLeft + 232, guiTop + 71, 150, 20, "script.openfolder"));
}
@@ -335,9 +340,13 @@ public class GuiScript extends GuiScriptInterface {
}
if (guibutton.id == 107) {
ScriptContainer container = getCurrentContainer();
if (container == null)
script.setNPCScript(activeTab, container = new ScriptContainer(this.script));
setSubGui(new GuiScriptList(languages.get(script.scriptLanguage), container));
if (container == null) {
container = new ScriptContainer(this.script);
container.setLanguage(script.getLanguage());
script.setNPCScript(activeTab, container);
}
String lang = container.getLanguage();
setSubGui(new GuiScriptList(languages.get(lang), container));
}
}
@@ -345,8 +354,11 @@ public class GuiScript extends GuiScriptInterface {
protected void setScript() {
if (showScript) {
ScriptContainer container = getCurrentContainer();
if (container == null)
script.setNPCScript(activeTab, container = new ScriptContainer(this.script));
if (container == null) {
container = new ScriptContainer(this.script);
container.setLanguage(script.getLanguage());
script.setNPCScript(activeTab, container);
}
String text = getTextField(2).getText();
text = text.replace("\r\n", "\n");
text = text.replace("\r", "\n");
@@ -47,6 +47,7 @@ public class GuiScriptInterface extends GuiNPCInterface implements GuiYesNoCallb
protected int scriptLimit = 1;
public List<String> hookList = new ArrayList<String>();
protected boolean loaded = false;
protected boolean serverDataReceived = false;
protected Map<Integer, GuiScriptTextArea> textAreas = new HashMap<>();
protected GuiScreen parent;
@@ -321,9 +322,12 @@ public class GuiScriptInterface extends GuiNPCInterface implements GuiYesNoCallb
this.addButton(new GuiNpcButton(100, left1, this.guiTop + 21 + yoffset, 60, 20, "gui.copy"));
this.addButton(new GuiNpcButton(105, left1 + 61, this.guiTop + 21 + yoffset, 60, 20, "gui.remove"));
// Language toggle button (only if handler supports Janino and there is more than one option)
if (handler.supportsJanino() && getLanguageOptions().size() > 1 && container != null) {
this.addButton(new GuiNpcButton(113, left1, this.guiTop + 42 + yoffset, 121, 20, container.getLanguage()));
// Per-tab language button — cycles through all available languages
List<String> langOptions = getLanguageOptions();
if (langOptions.size() > 1 && container != null) {
int langIdx = getContainerLanguageIndex(langOptions, container);
this.addButton(new GuiNpcButton(113, left1, this.guiTop + 42 + yoffset, 121, 20,
langOptions.toArray(new String[0]), langIdx));
}
this.addButton(new GuiNpcButton(107, left1, this.guiTop + 66 + yoffset, 80, 20, "script.loadscript"));
@@ -352,16 +356,20 @@ public class GuiScriptInterface extends GuiNPCInterface implements GuiYesNoCallb
int var9 = this.guiLeft + this.xSize - 150;
this.addButton(new GuiNpcButton(100, var9, this.guiTop + 125, 60, 20, "gui.copy"));
this.addButton(new GuiNpcButton(102, var9, this.guiTop + 146, 60, 20, "gui.clear"));
this.addLabel(new GuiNpcLabel(1, "script.language", var9, this.guiTop + 15));
this.addLabel(new GuiNpcLabel(1, "script.default", var9, this.guiTop + 15));
List<String> languageOptions = getLanguageOptions();
this.addButton(new GuiNpcButton(103, var9 + 60, this.guiTop + 10, 80, 20,
languageOptions.toArray(new String[0]),
this.getLanguageIndex(languageOptions)));
this.getButton(103).enabled = languageOptions.size() > 0;
this.addLabel(new GuiNpcLabel(2, "gui.enabled", var9, this.guiTop + 36));
this.addButton(new GuiNpcButton(104, var9 + 60, this.guiTop + 31, 50, 20,
new String[]{"gui.no", "gui.yes"}, this.handler.getEnabled() ? 1 : 0));
// Disable language/enabled controls until server data actually arrives
// (serverDataReceived is only set in loadLanguagesData, not by getLanguageOptions injecting Java)
this.getButton(103).enabled = serverDataReceived && languageOptions.size() > 0;
this.getButton(104).enabled = serverDataReceived;
if (this.player.worldObj.isRemote) {
this.addButton(new GuiNpcButton(106, var9, this.guiTop + 55, 150, 20, "script.openfolder"));
}
@@ -478,6 +486,26 @@ public class GuiScriptInterface extends GuiNPCInterface implements GuiYesNoCallb
return 0;
}
/**
* Finds the index of a container's language within the available options.
* Used for the per-tab language button (113).
*
* @param languageOptions The list of available languages.
* @param container The script unit whose language to find.
* @return The 0-based index, or 0 if not found.
*/
protected int getContainerLanguageIndex(List<String> languageOptions, IScriptUnit container) {
if (languageOptions == null || languageOptions.isEmpty() || container == null)
return 0;
String current = container.getLanguage();
for (int i = 0; i < languageOptions.size(); i++) {
if (current != null && languageOptions.get(i).equalsIgnoreCase(current))
return i;
}
return 0;
}
/**
* Retrieves the list of available scripting languages for this handler.
* <p>
@@ -602,13 +630,13 @@ public class GuiScriptInterface extends GuiNPCInterface implements GuiYesNoCallb
if (guibutton.id == scriptLimit) {
if (handler.isSingleContainer()) {
if (handler.getSingleScript() == null) {
handler.addScriptUnit(new ScriptContainer(handler));
handler.addScriptUnit(createDefaultScriptUnit());
} else {
this.setScript();
}
this.activeTab = 1;
} else {
handler.addScriptUnit(new ScriptContainer(this.handler));
handler.addScriptUnit(createDefaultScriptUnit());
this.activeTab = this.handler.getScripts().size();
}
this.initGui();
@@ -666,43 +694,47 @@ public class GuiScriptInterface extends GuiNPCInterface implements GuiYesNoCallb
if (guibutton.id == 107) {
IScriptUnit container = getCurrentContainer();
if (container == null) {
container = new ScriptContainer(this.handler);
container = createDefaultScriptUnit();
handler.addScriptUnit(container);
}
String language = container != null ? container.getLanguage() : this.handler.getLanguage();
String language = container.getLanguage();
this.setSubGui(new EventGuiScriptList((List) this.languages.get(language), container));
}
// Language toggle button - switch between ECMAScript and Java
// Per-tab language cycling button
if (guibutton.id == 113) {
String selectedLanguage = ((GuiNpcButton) guibutton).displayString;
int idx = getActiveScriptIndex();
if (idx >= 0 && idx < handler.getScripts().size()) {
IScriptUnit currentUnit = handler.getScripts().get(idx);
IScriptUnit newUnit;
boolean currentIsJanino = currentUnit.isJanino();
boolean targetIsJanino = "Java".equals(selectedLanguage);
if (currentUnit.isJanino()) {
// Switch from Java to ECMAScript
newUnit = new ScriptContainer(handler);
if (currentIsJanino && !targetIsJanino) {
// Switch from Java to a non-Java language
IScriptUnit newUnit = new ScriptContainer(handler);
newUnit.setScript(currentUnit.getScript());
newUnit.setExternalScripts(new ArrayList<>(currentUnit.getExternalScripts()));
} else {
// Switch from ECMAScript to Java
newUnit = handler.createJaninoScriptUnit();
handler.replaceScriptUnit(idx, newUnit);
textAreas.remove(idx);
initGui();
} else if (!currentIsJanino && targetIsJanino) {
// Switch from non-Java to Java
IScriptUnit newUnit = handler.createJaninoScriptUnit();
if (newUnit != null) {
newUnit.setScript(currentUnit.getScript());
newUnit.setExternalScripts(new ArrayList<>(currentUnit.getExternalScripts()));
} else {
return; // Handler doesn't support Janino
handler.replaceScriptUnit(idx, newUnit);
textAreas.remove(idx);
initGui();
}
} else if (!currentIsJanino) {
// Switch between non-Java languages (e.g., ECMAScript to Lua)
currentUnit.setLanguage(selectedLanguage);
GuiScriptTextArea area = getActiveScriptArea();
if (area != null) area.setLanguage(selectedLanguage);
}
handler.replaceScriptUnit(idx, newUnit);
// Clear the cached text area so it recreates with new language
textAreas.remove(idx);
// Reinitialize the GUI
initGui();
}
}
}
@@ -712,7 +744,7 @@ public class GuiScriptInterface extends GuiNPCInterface implements GuiYesNoCallb
IScriptUnit container = getCurrentContainer();
if (container == null) {
container = new ScriptContainer(this.handler);
container = createDefaultScriptUnit();
handler.addScriptUnit(container);
}
@@ -782,6 +814,7 @@ public class GuiScriptInterface extends GuiNPCInterface implements GuiYesNoCallb
}
this.languages = languages;
this.serverDataReceived = true;
this.initGui();
}
@@ -831,6 +864,22 @@ public class GuiScriptInterface extends GuiNPCInterface implements GuiYesNoCallb
super.close();
}
/**
* Create a new script unit using the handler's default language.
* If default is Java, creates a JaninoScript; otherwise a ScriptContainer
* with its language set to the handler's default.
*/
protected IScriptUnit createDefaultScriptUnit() {
String defaultLang = handler.getLanguage();
if ("Java".equals(defaultLang)) {
IScriptUnit unit = handler.createJaninoScriptUnit();
if (unit != null) return unit;
}
ScriptContainer sc = new ScriptContainer(handler);
sc.setLanguage(defaultLang);
return sc;
}
// ==================== FULLSCREEN METHODS ====================
/**
@@ -155,9 +155,21 @@ public enum EnumScriptType {
public String function;
private static final java.util.Map<String, EnumScriptType> BY_FUNCTION = new java.util.HashMap<>();
static {
for (EnumScriptType type : values()) {
BY_FUNCTION.put(type.function, type);
}
}
public static EnumScriptType valueOfIgnoreCase(String channelName) {
channelName = channelName.toUpperCase();
return valueOf(channelName);
// First try by function name (e.g. "abilityStart")
EnumScriptType type = BY_FUNCTION.get(channelName);
if (type != null) {
return type;
}
// Fallback to enum constant name (e.g. "ABILITY_START")
return valueOf(channelName.toUpperCase());
}
private EnumScriptType(String function) {
@@ -46,6 +46,12 @@ public class ScriptContainer implements IScriptUnit {
private CompiledScript compScript = null;
private final HashMap<String, ScriptObjectMirror> cachedFunctions = new HashMap<>();
/**
* Persisted per-container language. Null means inherit from handler default.
* Separate from currentScriptLanguage which is the engine cache.
*/
private String language = null;
public ScriptContainer(IScriptHandler handler) {
this.handler = handler;
}
@@ -68,6 +74,12 @@ public class ScriptContainer implements IScriptUnit {
this.console = NBTTags.GetLongStringMap(compound.getTagList("Console", 10));
this.scripts = NBTTags.getStringList(compound.getTagList("ScriptList", 10));
this.lastCreated = 0L;
// Read per-container language (empty string or missing = inherit from handler)
if (compound.hasKey("ContainerLanguage")) {
String lang = compound.getString("ContainerLanguage");
this.language = lang.isEmpty() ? null : lang;
}
}
public NBTTagCompound writeToNBT(NBTTagCompound compound) {
@@ -98,6 +110,11 @@ public class ScriptContainer implements IScriptUnit {
//compound.setString("Type", this.type);
compound.setTag("Console", NBTTags.NBTLongStringMap(this.console));
compound.setTag("ScriptList", NBTTags.nbtStringList(this.scripts));
// Persist per-container language if explicitly set
if (this.language != null) {
compound.setString("ContainerLanguage", this.language);
}
return compound;
}
@@ -169,7 +186,7 @@ public class ScriptContainer implements IScriptUnit {
if (!CustomNpcs.proxy.isScriptingEnabled() || errored || !hasCode() || unknownFunctions.contains(type))
return;
this.setEngine(handler.getLanguage());
this.setEngine(this.getLanguage());
if (engine == null)
return;
@@ -308,18 +325,15 @@ public class ScriptContainer implements IScriptUnit {
@Override
public String getLanguage() {
// If a specific language is set for this container, use it
// Otherwise fall back to the handler's language
if (currentScriptLanguage != null) {
return currentScriptLanguage;
}
return handler != null ? handler.getLanguage() : "ECMAScript";
// Return persisted per-container language, defaulting to ECMAScript.
// This is separate from currentScriptLanguage which is the engine cache.
return this.language != null ? this.language : "ECMAScript";
}
@Override
public void setLanguage(String language) {
if (!Objects.equals(this.currentScriptLanguage, language)) {
this.currentScriptLanguage = language;
if (!Objects.equals(this.language, language)) {
this.language = language;
this.evaluated = false;
}
}
@@ -18,6 +18,7 @@ import noppes.npcs.constants.ScriptContext;
import noppes.npcs.controllers.ScriptContainer;
import noppes.npcs.controllers.ScriptController;
import noppes.npcs.controllers.ScriptHookController;
import noppes.npcs.janino.EventJaninoScript;
import org.apache.commons.lang3.StringUtils;
import java.io.IOException;
@@ -161,6 +162,11 @@ public class ForgeDataScript extends MultiScriptHandler {
ForgeScriptPacket.Save(index, totalCount, nbt);
}
@Override
public IScriptUnit createJaninoScriptUnit() {
return new EventJaninoScript(ScriptContext.FORGE);
}
@Override
public boolean isClient() {
return false;
@@ -8,6 +8,7 @@ import noppes.npcs.api.entity.ICustomNpc;
import noppes.npcs.constants.ScriptContext;
import noppes.npcs.controllers.ScriptController;
import noppes.npcs.entity.EntityNPCInterface;
import noppes.npcs.janino.EventJaninoScript;
import noppes.npcs.scripted.NpcAPI;
import noppes.npcs.util.ScriptToStringHelper;
@@ -47,6 +48,11 @@ public class GlobalNPCDataScript extends MultiScriptHandler {
lastNpcUpdate = ScriptController.Instance.lastGlobalNpcUpdate;
}
@Override
public IScriptUnit createJaninoScriptUnit() {
return new EventJaninoScript(ScriptContext.NPC);
}
@Override
public void requestData() {
GlobalNPCScriptPacket.Get();
@@ -167,6 +167,12 @@ public class PlayerDataScript extends MultiScriptHandler {
return ScriptController.Instance.playerScripts.scriptLanguage;
}
@Override
public void setLanguage(String lang) {
ScriptController.Instance.playerScripts.scriptLanguage = lang;
this.scriptLanguage = lang;
}
@Override
public String noticeString() {
if (this.player == null) {
@@ -87,6 +87,11 @@ public class ScriptLinkedItem extends ScriptCustomizableItem implements IItemLin
return this.durabilityValue;
}
public void setDurabilityValue(float value) {
this.durabilityValue = (double) value;
saveItemData();
}
@Override
public int getMaxItemUseDuration() {
return this.linkedItem.maxItemUseDuration;
@@ -217,6 +222,7 @@ public class ScriptLinkedItem extends ScriptCustomizableItem implements IItemLin
this.itemDisplay.writeToNBT(compound);
compound.setTag(LinkedItem.LINKED_DATA_NBT_TAG, this.linkedItem.writeToNBT(false));
compound.setInteger(LinkedItem.LINKED_VERSION_VERSION_TAG, this.linkedVersion);
compound.setDouble("DurabilityValue", this.durabilityValue);
return compound;
}
@@ -224,5 +230,7 @@ public class ScriptLinkedItem extends ScriptCustomizableItem implements IItemLin
this.itemDisplay.readFromNBT(compound);
this.linkedItem.readFromNBT(compound.getCompoundTag(LinkedItem.LINKED_DATA_NBT_TAG));
this.linkedVersion = compound.getInteger(LinkedItem.LINKED_VERSION_VERSION_TAG);
if (compound.hasKey("DurabilityValue"))
this.durabilityValue = compound.getDouble("DurabilityValue");
}
}
@@ -432,6 +432,7 @@ script.interact=interagieren
script.update=Update
script.console=Konsole
script.language=Sprache
script.default=Standard
script.damaged=Schaden
script.killed=Sterben
script.attack=Angriff
@@ -861,6 +861,7 @@ script.interact=Interact
script.update=Update
script.console=Console
script.language=Language
script.default=Default
script.damaged=Damaged
script.killed=Killed
script.attack=Attack
@@ -423,6 +423,7 @@ script.interact=상호작용
script.update=업데이트
script.console=콘솔
script.language=언어
script.default=기본
script.damaged=데미지
script.killed=사망
script.attack=공격
@@ -461,6 +461,7 @@ script.interact=Взаимодействие
script.update=Обновление
script.console=Консоль
script.language=Язык
script.default=По умолч.
script.damaged=Получ. урон
script.killed=Убит
script.attack=Атакует
@@ -641,6 +641,7 @@ script.interact=对话
script.update=更新
script.console=控制台
script.language=语言
script.default=默认
script.damaged=伤害
script.killed=杀死
script.attack=攻击