Files
dsrc/sku.0/sys.server/compiled/game/script/script_entry.java
Tekaoh 5c2e112349 Java 11.0.2 migration (#32)
* Code compiles - execution NOT tested

* updating gitignore

* Removed intellij settings files

* Removed more intellij files

* Added exclusion for JDK classes.

* Fixed purchasing script for vendors that have listed coin types.

* Updated script to not kick off until the entire preload is complete.

* adds static name entry for Solo movie poster and tcg9 vendor entry

* clean up empty and orphaned object templates

* adds placeholder black market (static) spawns

* corrects entries for the video game table to correctly set it in tcg series 2 and remove series 1 console errors

* Updated gitignore and removed intellij project files

* Fixed appearance reference for thranta payroll and kashyyyk door, added skipLosCheck objvar due to cannit see issue. Requires updated src

* Fixed appearance and template for terminal (#2)

* Fixed appearance and template for terminal (#3)

* Fixed appearance and template for terminal (#4)

* Deleted another faulty/orphaned object template

* Fixed gcw ranks option on frog. Only issue is that it doesn't award the officer commands or badges.

* Fixed some unneeded java 11 changes
2019-04-18 18:31:52 -05:00

1381 lines
44 KiB
Java
Executable File

/*
Title: script_entry
Description: Java entry point for executing scripts.
*/
package script;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;
public class script_entry
{
/**************************************************************************/
/**
* Class listener_data keeps track of what we need to do when a listened for
* function gets called.
*/
static class listener_data
{
private obj_id m_listener; // who is listening
private String m_script; // listener script to call
private String m_function; // listener function to call
public listener_data(obj_id listener, String script, String function)
{
m_listener = listener;
m_script = script;
m_function = function;
} // listener_data
public obj_id getListener()
{
return m_listener;
} // getListener
public String getScript()
{
return m_script;
} // getScript
public String getFunction()
{
return m_function;
} // getFunction
public boolean equals(Object obj)
{
// assume the object is a listener_data
try
{
listener_data data = (listener_data)obj;
if ( data.m_listener == m_listener )
return true;
return false;
}
catch( ClassCastException err )
{
}
// see if the object is an obj_id
try
{
obj_id data = (obj_id)obj;
if ( data == m_listener )
return true;
return false;
}
catch( ClassCastException err )
{
}
return false;
} // equals
} // class listener_data
/**************************************************************************/
// flag to enable profiling calls
private static boolean ENABLE_PROFILING = false;
private static boolean profileSettingInitialized = false;
private static void checkEnableProfiling()
{
String result = base_class.getConfigSetting("GameServer", "javaEngineProfiling");
boolean ret = (result != null && (result.equals("on") || result.equals("1") || result.equals("true")));
ENABLE_PROFILING = ret;
profileSettingInitialized = true;
}
// internal return value for triggers
private static final int SCRIPT_INTERNAL_ERROR = 99;
// starting value for listener hash tables
private static final int LISTENER_HASH_TABLE_SIZE = 30;
// members
private static String scriptPath; // path where scripts are
private static Hashtable scriptListeners = new Hashtable(); // scripts that are listening for other script functions to be called
// the table is keyed on the id of the object whose function we want
// to listen for, with the data being another Hashtable. The data
// Hashtable is keyed on the function being called, with the data
// being a list of objects who are listening for the function call.
private static Stack ownerContext = new Stack(); // obj_id of the object currently running a script
private static StringBuffer scriptNameBuffer = null;
private static Class[] messageHandlerClasses = null; // used to get the Method object for messageHandlers
private static dictionary messageHandlerDictionary = null; // used for messageHandlers with null params
private static boolean printDebugInfo = false; // flag to print debug info
private static boolean crashOnException = false; // flag to crash if an exception occurs
private static boolean enableJediTracking = false; // flag to track players to see if they can become Jedi
private static Stack runningScripts = new Stack(); // scripts being run
private static Stack runningMethods = new Stack(); // methods being run
private static long scriptStartTime = 0; // time at which a script started to run
private static long scriptWarnMs = 0; // length of time a script can run before we print a warning
private static long scriptInterruptMs = 0; // length of time a script can run before we stop it from running
private static boolean scriptWarnPrinted = false; // flag that we've printed a warning about scripts running long
private static int stackOverflowLengthLimit = 35; // depth of stack on a StackOverflowError we decide is a legit error
private static boolean crashOnStackOverflow = true; // flag to crash on StackOverflowError, if it below stackOverflowLengthLimit
/**************************************************************************/
/**
* Class constructor.
*
* @param path directory where the scripts are
*/
public script_entry(String path, boolean debug, boolean exception, int watcherWarnMs, int watcherInterruptMs,
int stackErrorLimit, boolean stackErrorCrash)
{
printDebugInfo = debug;
crashOnException = exception;
stackOverflowLengthLimit = stackErrorLimit;
crashOnStackOverflow = stackErrorCrash;
scriptPath = path;
// add a '/' to the end of the path if there isn't one
if (!scriptPath.endsWith("\\") && !scriptPath.endsWith("/"))
scriptPath = scriptPath + "/";
// start a watcher thread that will prevent scripts from running too long
if (watcherWarnMs > 0 && watcherInterruptMs > 0)
{
scriptWarnMs = watcherWarnMs;
scriptInterruptMs = watcherInterruptMs;
}
if (debug)
{
System.out.println("Java script_entry initialized, free/total Java memory = " + Runtime.getRuntime().freeMemory() +
"/" + Runtime.getRuntime().totalMemory());
}
} // script_entry
/**
* Turns script logging on or off.
*
* @param enable flag to turn logging on or off
*/
public static void enableScriptLogging(boolean enable)
{
printDebugInfo = enable;
}
/**
* Turns tracking of players to see if they can become Jedi on or off.
*
* @param enable flag to turn tracking on or off
*/
public static void enableNewJediTracking(boolean enable)
{
enableJediTracking = enable;
}
/**
* Returns if new Jedi tracking is enabled.
*/
public static boolean getEnableNewJediTracking()
{
return enableJediTracking;
}
/**
* Returns the script path.
*/
public static String getScriptPath()
{
return scriptPath;
} // getScriptPath
/**
* Finds the Class associated with a class name.
*
* @param name the class name
*
* @return the class
*/
public static Class getClass(String name) throws ClassNotFoundException
{
// find the class loader for the class
script_class_loader loader = script_class_loader.getClassLoader(name);
if (loader == null)
{
System.err.println("WARNING: ERROR in java class script_entry.getClass: cannot find loader for class " + name);
throw new ClassNotFoundException();
}
return loader.getMyClass();
} // getClass
/**
* Causes a class loader to be unloaded so that the class file will be
* re-read the next time the script is run.
*
* @param name the class name to unload
*
* @return true if the class was unloaded, false if the class doesn't exist
*/
public static boolean unloadClass(String name)
{
return script_class_loader.unloadClass(name);
} // unloadClass
/**
* Returns the available function names we can call on a script.
*
* @param script the script name
*
* @return an array of the available function names, or null on error
*/
public static String[] getScriptFunctions(String script) throws ClassNotFoundException
{
Class scriptClass = getClass(script);
if (scriptClass == null)
return null;
Class baseClass = getClass("script.base_class");
if (baseClass == null)
{
System.err.println("script_entry.java, getScriptFunctions could not find base class");
return null;
}
Class objectClass = Class.forName("java.lang.Object");
if (objectClass == null)
{
System.err.println("script_entry.java, getScriptFunctions could not find Object class");
return null;
}
Method[] scriptMethods = scriptClass.getMethods();
// put the function names into an array, filtering out functions that are derived from base_class.java
// and other non-script classes
Vector functions = new Vector();
for (Method scriptMethod : scriptMethods) {
if (scriptMethod.getDeclaringClass() != baseClass &&
scriptMethod.getDeclaringClass() != objectClass) {
functions.add(scriptMethod.getName());
}
}
// convert the Vector of function names to an array
String[] returnValue = new String[functions.size()];
functions.toArray(returnValue);
/*
System.out.println("script_entry.java, getScriptFunctions returning names for script " + script);
for ( int i = 0; i < returnValue.length; ++i )
{
System.out.println("\t" + returnValue[i]);
}
*/
return returnValue;
} // getScriptFunctions
/**
* Returns the obj_id of the object currently running scripts.
*
* @return the owner's obj_id
**/
static obj_id getOwnerContext()
{
return (obj_id)ownerContext.peek();
} // getOwnerContext
static long getScriptStartTime()
{
return scriptStartTime;
}
static long getScriptWarnMs()
{
return scriptWarnMs;
}
static long getScriptInterruptMs()
{
return scriptInterruptMs;
}
static String getCurrentScriptAndMethod()
{
if (!runningScripts.empty() && !runningMethods.empty())
{
return runningScripts.peek() + "." + runningMethods.peek();
}
return "<null>";
}
static void setScriptWarnPrinted()
{
scriptWarnPrinted = true;
}
static boolean isScriptWarnPrinted()
{
return scriptWarnPrinted;
}
private static void reportMemory(String msg)
{
long freeMem = Runtime.getRuntime().freeMemory();
long totalMem = Runtime.getRuntime().totalMemory();
System.err.println("WARNING: " + msg + ", memory = " + freeMem + "/" + totalMem);
}
public static long getFreeMemory()
{
return Runtime.getRuntime().freeMemory();
}
/**
* Executes a script.
*
* @param script name of the script
* @param method name of the script method to call
* @param params paramaters to pass to the method
*
* @return SCRIPT_CONTINUE or SCRIPT_OVERRIDE
*/
@SuppressWarnings("deprecation")
public static int runScript(String script, String method, Object[] params) throws internal_script_error, internal_script_exception
{
boolean scriptCalled = false;
boolean isProfiling = false;
if (!profileSettingInitialized)
checkEnableProfiling();
int result = base_class.SCRIPT_CONTINUE;
// System.out.println("*****pushing ownerContext, script = " + script + ", method = " + method + ", count = " +
// Integer.toString(ownerContext.size()) + "*****");
ownerContext.push(params[0]);
Hashtable methods = null;
try
{
script_class_loader loader = script_class_loader.getClassLoader(script);
if (loader == null)
{
System.err.println("WARNING: couldn't load script " + script);
return result;
}
Class cls = loader.getMyClass();
if (cls == null)
{
System.err.println("WARNING: couldn't get class for script " + script);
return result;
}
Object obj = loader.getMyObject();
if (obj == null)
{
System.err.println("WARNING: couldn't get object for script " + script);
return result;
}
methods = loader.getMyMethods();
if (methods == null)
{
System.err.println("WARNING: couldn't get methods for script " + script);
return result;
}
// System.out.println("Got loader and class for script " + script);
Method meth = (Method)methods.get(method);
if (meth == null)
{
if (params == null)
{
meth = cls.getDeclaredMethod(method);
}
else
{
// get the parameter classes
String paramClassName;
Class[] paramClass = new Class[params.length];
for (int i = 0; i < params.length; ++i)
{
if (params[i] == null)
{
paramClass = null;
System.err.println("ERROR: Calling script \"" + script + "\" method \"" + method + "\" parameter " + i + " is null!");
break;
}
if (params[i] instanceof Integer)
paramClass[i] = java.lang.Integer.TYPE;
else if (params[i] instanceof Float)
paramClass[i] = java.lang.Float.TYPE;
else if (params[i] instanceof Boolean)
paramClass[i] = java.lang.Boolean.TYPE;
else
paramClass[i] = params[i].getClass();
}
if (paramClass != null)
meth = cls.getMethod(method, paramClass);
}
// cache the method
if (meth != null)
{
if (meth.isAccessible() == false)
meth.setAccessible(true);
methods.put(method, meth);
}
}
if (meth != null && meth != script_class_loader.NO_METHOD)
{
scriptCalled = true;
if (printDebugInfo)
System.out.println("Java runScript enter, script = " + script + ", method = " + method);
startScriptTimer(script, method);
if (ENABLE_PROFILING)
{
isProfiling = true;
base_class.PROFILER_START(script + "." + method);
}
Object scriptResult = meth.invoke(obj, params);
if ( scriptResult != null )
result = (Integer) scriptResult;
}
}
catch (NoSuchMethodException err)
{
// System.err.println("Error getting method " + method + " in script " + script);
// store a dummy method tag in the methods table to avoid looking up this method again
if (methods != null)
methods.put(method, script_class_loader.NO_METHOD);
result = base_class.SCRIPT_CONTINUE;
}
catch (InvocationTargetException err)
{
if ( err != null )
{
Throwable realErr = err.getTargetException();
if (realErr != null)
{
if (realErr instanceof internal_script_error)
{
System.err.println("WARNING: " + realErr);
err.printStackTrace(System.err);
throw (internal_script_error)realErr;
}
else if (realErr instanceof internal_script_exception)
{
System.err.println("WARNING: " + realErr);
err.printStackTrace(System.err);
throw (internal_script_exception)realErr;
}
System.err.println("WARNING: Java Error: InvocationTargetException for script " + script + ", trigger " + method);
System.err.println("WARNING: " + realErr);
if (realErr instanceof Error)
{
System.err.println("WARNING: Major error! Printing stack trace:");
err.printStackTrace(System.err);
if (realErr instanceof StackOverflowError)
{
reportMemory("Java stack overflow");
if (crashOnStackOverflow)
crashOnException = true;
else
throw new internal_script_error((Error)realErr);
}
else
throw new internal_script_error((Error)realErr);
}
else
err.printStackTrace(System.err);
}
else
System.err.println("WARNING: Java Error: Unknown InvocationTargetException.getTargetException for script " + script + ", trigger " + method);
}
else
System.err.println("WARNING: Java Error: Unknown InvocationTargetException for script " + script + ", trigger " + method);
if (crashOnException)
{
base_class.disableGameMemoryDump();
base_class.generateJavacore();
System.exit(-1);
}
result = SCRIPT_INTERNAL_ERROR;
}
catch (ClassNotFoundException err)
{
System.err.println("WARNING: Java Error: " + err + ", trigger = " + method);
result = base_class.SCRIPT_CONTINUE;
}
catch (StackOverflowError err)
{
reportMemory("Java stack overflow");
System.err.println("WARNING: Java Error in runScript from calling " + method + " : " + err);
err.printStackTrace(System.err);
System.err.println("WARNING: current stack = ");
Thread.dumpStack();
// com.ibm.jvm.Dump.JavaDump();
if (crashOnStackOverflow)
{
base_class.generateJavacore();
System.exit(-1);
}
else
result = SCRIPT_INTERNAL_ERROR;
}
catch (Exception err)
{
// any other exception is an error
System.err.println("WARNING: Java Error: Unhandled Exception for script " + script + ", trigger " + method);
System.err.println("WARNING: " + err);
result = SCRIPT_INTERNAL_ERROR;
}
catch (Error err)
{
if (err instanceof internal_script_error)
throw (internal_script_error)err;
System.err.println("WARNING: Java Error: Unhandled Error for script " + script + ", trigger " + method);
System.err.println("WARNING: " + err.toString());
result = SCRIPT_INTERNAL_ERROR;
}
finally
{
if (scriptCalled)
{
stopScriptTimer();
if (printDebugInfo)
System.out.println("Java runScript exit, script = " + script + ", trigger = " + method);
}
ownerContext.pop();
if (isProfiling)
base_class.PROFILER_STOP(script + "." + method);
}
return result;
} // runScript
/**
* Executes all the scripts attached to an object. It is assumed that the
* 1st parameter of params is the obj_id of the object we want to run the
* scripts on.
*
* @param method name of the script method to call
* @param params paramaters to pass to the method
*
* @return SCRIPT_CONTINUE or SCRIPT_OVERRIDE
*/
public static int runScripts(String method, Object[] params) throws internal_script_error
{
if (params == null || params.length == 0 || params[0] == null)
{
System.err.println("WARNING: Java script_entry.runScripts ERROR: invalid params");
return base_class.SCRIPT_OVERRIDE;
}
obj_id object;
try
{
object = (obj_id)params[0];
}
catch (ClassCastException err)
{
System.err.println("WARNING: Java script_entry.runScripts ERROR: param[0] not self");
return base_class.SCRIPT_OVERRIDE;
}
if (object.getValue() == 0 || !object.isAuthoritative() || !object.isLoaded())
{
boolean doubleCheck = false;
String warning = "WARNING: Java script_entry.runScripts ERROR calling script function " + method + ": invalid self:";
if (object.getValue() == 0) {
warning += "\n- obj_id is 0.";
}
if (!object.isAuthoritative()) {
warning += "\n- object is not authoritative";
// We've seen errors where Java thinks an object is non-authoritative but C thinks the object
// is authoritative. _internalIsAuthoritative() will double-check for us and set the obj_id
// flag if needed
doubleCheck = base_class._internalIsAuthoritative(object);
warning += (
doubleCheck
? " (" + object + " is flagged as non-authoritative in Java but is authoritative in C.)"
: "."
);
}
if (!object.isLoaded())
warning += "\n- " + object + " is not loaded.";
if(printDebugInfo) System.err.println(warning);
if (!doubleCheck)
return base_class.SCRIPT_OVERRIDE;
}
object.lockScripts(); // prevent the object's script list from being modified
int result = base_class.SCRIPT_CONTINUE;
try
{
if(object.getLockCount() > 1)
{
String[] scripts = object.getScripts();
if(scripts != null) {
for (String script : scripts) {
result = runScript(script, method, params);
if (result != base_class.SCRIPT_CONTINUE)
break;
}
}
}
else
{
ArrayList scripts = object.getScriptArrayList();
for (Object script : scripts) {
// String script = (String)scripts.get(i);
// System.out.println("IN JAVA: script_entry.runScripts executing method " + method + " on script " + (String)scripts.get(i));
// scriptNameBuffer.setLength("script.".length());
// scriptNameBuffer.append(script);
// result = runScript(scriptNameBuffer.toString(), method, params);
result = runScript((String) script, method, params);
if (result != base_class.SCRIPT_CONTINUE)
break;
}
}
}
catch (ClassCastException err)
{
System.err.println("WARNING: Java script_entry.runScripts ERROR: non-string on script list!?!?");
result = base_class.SCRIPT_OVERRIDE;
}
catch (IndexOutOfBoundsException err)
{
System.err.println("WARNING: Java script_entry.runScripts ERROR: script list out of bounds!");
result = base_class.SCRIPT_OVERRIDE;
}
catch( internal_script_exception err )
{
result = SCRIPT_INTERNAL_ERROR;
}
finally
{
object.unlockScripts(); // allow modification to the object's scripts
}
return result;
} // runScripts
/**
* Executes a messageHandler.
*
* @param script name of the script
* @param method name of the script method to call
* @param params paramaters to pass to the method
*
* @return SCRIPT_CONTINUE or SCRIPT_OVERRIDE
*/
@SuppressWarnings("deprecation")
public static int callMessageHandler(String script, String method, Object[] params) throws internal_script_error, internal_script_exception
{
boolean scriptCalled = false;
boolean isProfiling = false;
// System.out.println("(java) runScript: script = " + script +
// ", method = " + method + ", num params = " + params.length);
int result = base_class.SCRIPT_CONTINUE;
// System.out.println("*****pushing ownerContext, script = " + script + ", method = " + method + ", count = " +
// Integer.toString(ownerContext.size()) + "*****");
ownerContext.push(params[0]);
Hashtable methods = null;
try
{
script_class_loader loader = script_class_loader.getClassLoader(script);
if (loader == null)
{
System.err.println("WARNING: couldn't load script " + script);
return result;
}
Class cls = loader.getMyClass();
if (cls == null)
{
System.err.println("WARNING: couldn't get class for script " + script);
return result;
}
Object obj = loader.getMyObject();
if (obj == null)
{
System.err.println("WARNING: couldn't get object for script " + script);
return result;
}
methods = loader.getMyMethods();
if (methods == null)
{
System.err.println("WARNING: couldn't get methods for script " + script);
return result;
}
// System.out.println("Got loader and class for script " + script);
Method meth = (Method)methods.get(method);
if (meth == null)
{
// get the parameter classes
meth = cls.getMethod(method, messageHandlerClasses);
// cache the method
if (meth != null)
{
if (meth.isAccessible() == false)
meth.setAccessible(true);
methods.put(method, meth);
}
}
if (meth != null && meth != script_class_loader.NO_METHOD)
{
scriptCalled = true;
if (printDebugInfo)
System.out.println("Java callMessageHandler enter, script = " + script + ", messageHandler = " + method);
startScriptTimer(script, method);
if (ENABLE_PROFILING)
{
isProfiling = true;
base_class.PROFILER_START(script + "." + method);
}
Object scriptResult = meth.invoke(obj, params);
if ( scriptResult != null )
result = (Integer) scriptResult;
}
}
catch (NoSuchMethodException err)
{
// System.err.println("Error getting method " + method + " in script " + script);
// store a dummy method tag in the methods table to avoid looking up this method again
if (methods != null)
methods.put(method, script_class_loader.NO_METHOD);
result = base_class.SCRIPT_CONTINUE;
}
catch (InvocationTargetException err)
{
if ( err != null )
{
Throwable realErr = err.getTargetException();
if (realErr != null)
{
if (realErr instanceof internal_script_error)
{
System.err.println("WARNING: " + realErr);
err.printStackTrace(System.err);
throw (internal_script_error)realErr;
}
else if (realErr instanceof internal_script_exception)
{
System.err.println("WARNING: " + realErr);
err.printStackTrace(System.err);
throw (internal_script_exception)realErr;
}
System.err.println("WARNING: Java Error: InvocationTargetException for script " + script + ", messageHandler " + method);
System.err.println("WARNING: " + realErr);
if (realErr instanceof Error)
{
System.err.println("WARNING: Major error! Printing stack trace:");
err.printStackTrace(System.err);
if (realErr instanceof StackOverflowError)
{
reportMemory("Java stack overflow");
if (crashOnStackOverflow)
crashOnException = true;
else
throw new internal_script_error((Error)realErr);
}
else
throw new internal_script_error((Error)realErr);
}
else
err.printStackTrace(System.err);
}
else
System.err.println("WARNING: Java Error: Unknown InvocationTargetException.getTargetException for script " + script + ", messageHandler " + method);
}
else
System.err.println("WARNING: Java Error: Unknown InvocationTargetException for script " + script + ", messageHandler " + method);
if (crashOnException)
{
base_class.disableGameMemoryDump();
base_class.generateJavacore();
System.exit(-1);
}
result = SCRIPT_INTERNAL_ERROR;
}
catch (ClassNotFoundException err)
{
System.err.println("WARNING: Java Error: " + err + ", messageHandler = " + method);
result = base_class.SCRIPT_CONTINUE;
}
catch (StackOverflowError err)
{
reportMemory("Java stack overflow");
System.err.println("WARNING: Java Error in callMessageHandler from calling " + method + " : " + err);
err.printStackTrace(System.err);
System.err.println("WARNING: current stack = ");
Thread.dumpStack();
// com.ibm.jvm.Dump.JavaDump();
if (crashOnStackOverflow)
{
base_class.generateJavacore();
System.exit(-1);
}
else
result = SCRIPT_INTERNAL_ERROR;
}
catch (Exception err)
{
// any other exception is an error
System.err.println("WARNING: Java Error: Unhandled Exception for script " + script + ", messageHandler " + method);
System.err.println("WARNING: " + err);
result = SCRIPT_INTERNAL_ERROR;
}
catch (Error err)
{
if (err instanceof internal_script_error)
throw (internal_script_error)err;
System.err.println("WARNING: Java Error: Unhandled Error for script " + script + ", messageHandler " + method);
System.err.println("WARNING: " + err.toString());
result = SCRIPT_INTERNAL_ERROR;
}
finally
{
if (scriptCalled)
{
stopScriptTimer();
if (printDebugInfo)
System.out.println("Java callMessageHandler exit, script = " + script + ", messageHandler = " + method);
}
ownerContext.pop();
if (isProfiling)
base_class.PROFILER_STOP(script + "." + method);
}
return result;
} // callMessageHandler
/**
* Executes a messageHandler for all the scripts attached to an object.
*
* @param method name of the script method to call
* @param object the object to run the scripts on
* @param params the dictionary containing the handler's params
*
* @return SCRIPT_CONTINUE or SCRIPT_OVERRIDE
*/
public static int callMessageHandlers(String method, long object, dictionary params) throws internal_script_error
{
return callMessageHandlers(method, (object == 0) ? null : obj_id.getObjId(object), params);
}
public static int callMessageHandlers(String method, obj_id object, dictionary params) throws internal_script_error
{
if (printDebugInfo)
System.out.println("Java callMessageHandlers enter, method = " + method + ", current time = " + System.currentTimeMillis());
if (messageHandlerClasses == null)
{
System.err.println("WARNING: Java script_entry.callMessageHandlers ERROR: messageHandlerClasses not initialized");
return base_class.SCRIPT_OVERRIDE;
}
if (method == null || object == null)
{
if (object == null)
System.err.println("WARNING: Java script_entry.callMessageHandlers ERROR: null self");
else
System.err.println("WARNING: Java script_entry.callMessageHandlers ERROR: null method name");
return base_class.SCRIPT_OVERRIDE;
}
if (object.getValue() == 0 || !object.isAuthoritative() || !object.isLoaded())
{
boolean doubleCheck = false;
if (object.getValue() == 0)
System.err.println("WARNING: Java script_entry.callMessageHandlers ERROR: invalid self: obj_id 0");
else if (!object.isAuthoritative())
{
System.err.println("WARNING: Java script_entry.callMessageHandlers ERROR: invalid self: " + object.toString() + " not authoritative");
// We've seen errors where Java thinks an object is non-authoritative but C thinks the object
// is authoritative. _internalIsAuthoritative() will double-check for us and set the obj_id
// flag if needed
doubleCheck = base_class._internalIsAuthoritative(object);
if (doubleCheck)
{
System.err.println("WARNING: object " + object + " is flagged as non-authoritative "+
"in Java but is authoritative in C");
}
}
else if (!object.isLoaded())
System.err.println("WARNING: Java script_entry.callMessageHandlers ERROR: invalid self: " + object.toString() + " not loaded");
if (!doubleCheck)
return base_class.SCRIPT_OVERRIDE;
}
object.lockScripts(); // prevent the object's script list from being modified
int result = base_class.SCRIPT_CONTINUE;
try
{
// create an array for the parameters that will be sent to Method.invoke()
Object[] paramArray = new Object[2];
paramArray[0] = object;
if (params != null)
paramArray[1] = params;
else
{
messageHandlerDictionary.clear();
paramArray[1] = messageHandlerDictionary;
}
if(object.getLockCount() > 1)
{
String[] scripts = object.getScripts();
for (String script : scripts) {
result = callMessageHandler(script, method, paramArray);
if (result != base_class.SCRIPT_CONTINUE)
break;
}
}
else
{
ArrayList scripts = object.getScriptArrayList();
for (Object script : scripts) {
// String script = "script." + (String)scripts.get(i);
// scriptNameBuffer.setLength("script.".length());
// scriptNameBuffer.append(script);
// script = scriptNameBuffer.toString();
// result = callMessageHandler(scriptNameBuffer.toString(), method, paramArray);
result = callMessageHandler((String) script, method, paramArray);
if (result != base_class.SCRIPT_CONTINUE)
break;
}
}
}
catch (ClassCastException err)
{
System.err.println("WARNING: Java script_entry.runScripts ERROR: non-string on script list!?!?");
result = base_class.SCRIPT_OVERRIDE;
}
catch (IndexOutOfBoundsException err)
{
System.err.println("WARNING: Java script_entry.runScripts ERROR: script list out of bounds!");
result = base_class.SCRIPT_OVERRIDE;
}
catch( internal_script_exception err )
{
result = SCRIPT_INTERNAL_ERROR;
}
finally
{
object.unlockScripts(); // allow modification to the object's scripts
}
return result;
} // callMessageHandlers
/**
* Executes a console handler function on a script. The hander must return a string instead of
* an int, and has no "self" parameter.
*
* @param script name of the script
* @param method name of the script method to call
* @param params paramaters to pass to the method
*
* @return the string returned from the handler function
*/
@SuppressWarnings("deprecation")
public static String runConsoleHandler(String script, String method, Object[] params) throws internal_script_error, internal_script_exception
{
boolean scriptCalled = false;
boolean isProfiling = false;
if (!profileSettingInitialized)
checkEnableProfiling();
String result = null;
Hashtable methods = null;
try
{
script_class_loader loader = script_class_loader.getClassLoader(script);
if (loader == null)
{
System.err.println("WARNING: couldn't load script " + script);
return result;
}
Class cls = loader.getMyClass();
if (cls == null)
{
System.err.println("WARNING: couldn't get class for script " + script);
return result;
}
Object obj = loader.getMyObject();
if (obj == null)
{
System.err.println("WARNING: couldn't get object for script " + script);
return result;
}
methods = loader.getMyMethods();
if (methods == null)
{
System.err.println("WARNING: couldn't get methods for script " + script);
return result;
}
Method meth = null;
if (params == null)
{
meth = cls.getDeclaredMethod(method);
}
else
{
// get the parameter classes
String paramClassName;
Class[] paramClass = new Class[params.length];
for (int i = 0; i < params.length; ++i)
{
if (params[i] == null)
{
paramClass = null;
System.err.println("WARNING: ERROR: param " + i + " is null!");
break;
}
if (params[i] instanceof Integer)
paramClass[i] = java.lang.Integer.TYPE;
else if (params[i] instanceof Float)
paramClass[i] = java.lang.Float.TYPE;
else if (params[i] instanceof Boolean)
paramClass[i] = java.lang.Boolean.TYPE;
else
paramClass[i] = params[i].getClass();
}
if (paramClass != null)
meth = cls.getMethod(method, paramClass);
}
if (meth != null && meth != script_class_loader.NO_METHOD)
{
if (meth.isAccessible() == false)
meth.setAccessible(true);
scriptCalled = true;
if (printDebugInfo)
System.out.println("Java runConsoleHandler enter, script = " + script + ", console handler method = " + method);
startScriptTimer(script, method);
if (ENABLE_PROFILING)
{
isProfiling = true;
base_class.PROFILER_START(script + "." + method);
}
Object scriptResult = meth.invoke(obj, params);
if ( scriptResult != null )
result = (String)scriptResult;
}
}
catch (NoSuchMethodException err)
{
}
catch (InvocationTargetException err)
{
if ( err != null )
{
Throwable realErr = err.getTargetException();
if (realErr != null)
{
if (realErr instanceof internal_script_error)
{
System.err.println("WARNING: " + realErr);
err.printStackTrace(System.err);
throw (internal_script_error)realErr;
}
else if (realErr instanceof internal_script_exception)
{
System.err.println("WARNING: " + realErr);
err.printStackTrace(System.err);
throw (internal_script_exception)realErr;
}
System.err.println("WARNING: Java Error: InvocationTargetException for script " + script +
", console handler method " + method);
System.err.println("WARNING: " + realErr);
if (realErr instanceof Error)
{
System.err.println("WARNING: Major error! Printing stack trace:");
err.printStackTrace(System.err);
if (realErr instanceof StackOverflowError)
{
reportMemory("Java stack overflow");
if (crashOnStackOverflow)
crashOnException = true;
else
throw new internal_script_error((Error)realErr);
}
else
throw new internal_script_error((Error)realErr);
}
else
err.printStackTrace(System.err);
}
else
{
System.err.println("WARNING: Java Error: Unknown InvocationTargetException.getTargetException for script " +
script + ", console handler method " + method);
}
}
else
{
System.err.println("WARNING: Java Error: Unknown InvocationTargetException for script " + script +
", console handler method " + method);
}
if (crashOnException)
{
base_class.disableGameMemoryDump();
base_class.generateJavacore();
System.exit(-1);
}
}
catch (ClassNotFoundException err)
{
System.err.println("WARNING: Java Error: " + err + ", console handler method = " + method);
}
catch (StackOverflowError err)
{
reportMemory("Java stack overflow");
System.err.println("WARNING: Java Error in runConsoleHandler from calling " + method + " : " + err);
err.printStackTrace(System.err);
System.err.println("WARNING: current stack = ");
Thread.dumpStack();
if (crashOnStackOverflow)
{
base_class.generateJavacore();
System.exit(-1);
}
}
catch (Exception err)
{
// any other exception is an error
System.err.println("WARNING: Java Error: Unhandled Exception for script " + script + ", console handler method " + method);
System.err.println("WARNING: " + err);
}
catch (Error err)
{
if (err instanceof internal_script_error)
throw (internal_script_error)err;
System.err.println("WARNING: Java Error: Unhandled Error for script " + script + ", console handler method " + method);
System.err.println("WARNING: " + err.toString());
}
finally
{
if (scriptCalled)
{
stopScriptTimer();
if (printDebugInfo)
System.out.println("Java runScript exit, script = " + script + ", console handler method = " + method);
}
if (isProfiling)
base_class.PROFILER_STOP(script + "." + method);
}
return result;
} // runConsoleHandler
/**
* Adds a listener to the list of scripts listening for function calls.
*
* @param listenee object who function we want to listen for
* @param listeneeFunction function name on listee we are listening for
* @param listener object listening for a function to be called
* @param listenerScript script on listener to call when the listenee function is called
* @param listenerFunction function name on listener to call when the listenee function is called
**/
public static void startScriptListening(obj_id listenee, String listeneeFunction,
obj_id listener, String listenerScript, String listenerFunction)
{
// make sure the listenee is authoritative
if (!listenee.isAuthoritative())
{
// @todo: send to authoritative object?
System.err.println("WARNING: Scripting error: trying to listen to non-authoritative object!");
System.err.println("WARNING: \tlistenee = " + listenee.toString() + ", function = " + listeneeFunction);
System.err.println("WARNING: \tlistener = " + listener.toString() + ", script = " + listenerScript + ", function = " + listenerFunction);
return;
}
Hashtable functions = (Hashtable)scriptListeners.get(listenee);
if (functions == null)
{
functions = new Hashtable(LISTENER_HASH_TABLE_SIZE);
scriptListeners.put(listenee, functions);
}
LinkedList listeners = (LinkedList)functions.get(listeneeFunction);
if (listeners == null)
{
listeners = new LinkedList();
functions.put(listeneeFunction, listeners);
}
listener_data data = new listener_data(listener, listenerScript, listenerFunction);
listeners.remove(data);
listeners.addFirst(data);
} // startScriptListening
/**
* Removes a listener from the list of scripts listening for function calls.
*
* @param listenee object that was being listened to
* @param listeneeFunction function name that was being listened for
* @param listener object that wants to stop listening
**/
public static void stopScriptListening(obj_id listenee, String listeneeFunction, obj_id listener)
{
Hashtable functions = (Hashtable)scriptListeners.get(listenee);
if ( functions != null )
{
LinkedList listeners = (LinkedList)functions.get(listeneeFunction);
if ( listeners != null )
{
listeners.remove(listener);
}
}
} // stopListening
/**
* Removes a listenee from the listeners list. This is generally done when the listenee is removed from the game.
*
* @param listenee the object we want to remove
**/
public static void removeScriptListenee(obj_id listenee)
{
scriptListeners.remove(listenee);
} // removeScriptListener
/**
* Calls any scripts that are listening for function calls on other scripts.
*
* @param listenee the script whose original function was called
* @param function function that was called on the listenee
* @param params parameters that were sent to the listenee's function
**/
public void callScriptListeners(obj_id listenee, String function, Object[] params) throws internal_script_error, internal_script_exception
{
Hashtable functions = (Hashtable)scriptListeners.get(listenee);
if (functions != null)
{
LinkedList listeners = (LinkedList)functions.get(function);
if (listeners != null && listeners.size() > 0)
{
// make the parameters to send to the listeners; they are the same as the ones sent to the listenee,
// but the 1st parameter is the listener's id
Object[] listenerParams = new Object[params.length + 1];
for ( int i = 0; i < params.length; ++i )
listenerParams[i+1] = params[i];
ListIterator i = listeners.listIterator(0);
for (listener_data listener = (listener_data)i.next(); listener != null; listener = (listener_data)i.next())
{
if (listener.getListener().getValue() != 0)
{
if (listener.getListener().isAuthoritative())
{
// call the listener's function
listenerParams[0] = listener.getListener();
runScript(listener.getScript(), listener.getFunction(), listenerParams);
}
else
{
// @todo: send a message to the authoritative object?
System.err.println("WARNING: Scripting error: trying to signal non-authoritative listener object!");
System.err.println("WARNING: \tlistener = " + listener.getListener().toString() +
", script = " + listener.getScript() + ", function = " + listener.getFunction());
}
}
else
{
// the listener is not in the game anymore, remove it from the list
i.remove();
}
}
}
}
} // callScriptListeners
/**
* Starts a timer for the current script.
*/
private static void startScriptTimer(String script, String method)
{
if (getScriptWarnMs() > 0 || getScriptInterruptMs() > 0)
{
runningScripts.push(script);
runningMethods.push(method);
scriptWarnPrinted = false;
scriptStartTime = System.currentTimeMillis();
}
}
/**
* Stops the timer for the current script.
*/
private static void stopScriptTimer()
{
if (getScriptWarnMs() > 0 || getScriptInterruptMs() > 0)
{
if (runningScripts.empty() || runningMethods.empty())
{
System.err.println("WARNING: Java script_entry.stopScriptTimer, " +
"m_runningScripts or m_runningMethods is empty! Shutting down scripting timeout.");
scriptWarnMs = 0;
scriptInterruptMs = 0;
scriptStartTime = 0;
return;
}
runningScripts.pop();
runningMethods.pop();
scriptWarnPrinted = false;
if (!runningScripts.empty())
{
// restart the timer for the current script
scriptStartTime = System.currentTimeMillis();
}
else
scriptStartTime = 0;
}
}
// initialize static data
static
{
scriptNameBuffer = new StringBuffer(512);
// scriptNameBuffer.append("script.");
try
{
messageHandlerClasses = new Class[2];
messageHandlerClasses[0] = obj_id.NULL_ID.getClass();
script_class_loader loader = script_class_loader.getClassLoader("script.dictionary");
messageHandlerClasses[1] = loader.getMyClass();
}
catch( ClassNotFoundException err )
{
messageHandlerClasses[0] = null;
messageHandlerClasses[1] = null;
}
if (messageHandlerClasses[0] == null || messageHandlerClasses[1] == null)
{
System.err.println("WARNING: Java script_entry.static ERROR: didn't initialize messageHandlerClasses");
messageHandlerClasses = null;
}
else
messageHandlerDictionary = new dictionary();
}
} // class script_entry