summaryrefslogtreecommitdiff
path: root/NET/worlds/scape/PosableShape.java
diff options
context:
space:
mode:
authorFuwn <[email protected]>2026-02-12 22:33:32 -0800
committerFuwn <[email protected]>2026-02-12 22:33:32 -0800
commitc7a9d4a6bd53ed7d61731770f2f10e8b9fd435f9 (patch)
treedf9f48bf128a6c0186a8e91857d6ff30fe0e9f18 /NET/worlds/scape/PosableShape.java
downloadworldsplayer-c7a9d4a6bd53ed7d61731770f2f10e8b9fd435f9.tar.xz
worldsplayer-c7a9d4a6bd53ed7d61731770f2f10e8b9fd435f9.zip
Initial commit
Diffstat (limited to 'NET/worlds/scape/PosableShape.java')
-rw-r--r--NET/worlds/scape/PosableShape.java1331
1 files changed, 1331 insertions, 0 deletions
diff --git a/NET/worlds/scape/PosableShape.java b/NET/worlds/scape/PosableShape.java
new file mode 100644
index 0000000..7ed5610
--- /dev/null
+++ b/NET/worlds/scape/PosableShape.java
@@ -0,0 +1,1331 @@
+package NET.worlds.scape;
+
+import NET.worlds.console.AvMenu;
+import NET.worlds.console.Console;
+import NET.worlds.console.DefaultConsole;
+import NET.worlds.core.IniFile;
+import NET.worlds.core.ServerTableManager;
+import NET.worlds.core.Std;
+import NET.worlds.core.Timer;
+import NET.worlds.core.TimerCallback;
+import NET.worlds.network.Cache;
+import NET.worlds.network.CacheFile;
+import NET.worlds.network.NetUpdate;
+import NET.worlds.network.URL;
+import NET.worlds.network.WorldServer;
+import java.awt.Color;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.net.MalformedURLException;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.StringTokenizer;
+import java.util.Vector;
+
+public class PosableShape extends Shape implements FrameHandler, Prerenderable, MouseDownHandler, ShapeLoaderListener, TimerCallback {
+ protected int figureType = -1;
+ private float closestView = 10000.0F;
+ private int farViewCount;
+ private Vector<String> animationList;
+ private boolean COG;
+ private boolean setPrepFigure = true;
+ private boolean runPrepFigure = this.setPrepFigure;
+ private static URL defaultURL = URL.make("avatar:aura.0PG.rwg");
+ protected DroneAnimator animator = null;
+ private boolean recomputeHeight = false;
+ private boolean firstURL = true;
+ private Shape subparts;
+ public static Color[] colorTable = new Color[]{
+ new Color(0, 0, 0),
+ new Color(51, 102, 204),
+ new Color(234, 162, 115),
+ new Color(255, 102, 51),
+ new Color(255, 153, 204),
+ new Color(139, 232, 0),
+ new Color(43, 131, 0),
+ new Color(51, 51, 153),
+ new Color(145, 51, 204),
+ new Color(153, 204, 255),
+ new Color(204, 51, 102),
+ new Color(0, 204, 102),
+ new Color(255, 204, 102),
+ new Color(102, 102, 102),
+ new Color(254, 123, 26),
+ new Color(255, 51, 153),
+ new Color(188, 51, 204),
+ new Color(204, 0, 38),
+ new Color(118, 0, 0),
+ new Color(153, 102, 51),
+ new Color(196, 196, 196),
+ new Color(204, 153, 255),
+ new Color(255, 255, 255),
+ new Color(255, 179, 2),
+ new Color(247, 227, 2),
+ new Color(255, 255, 153)
+ };
+ private Hashtable<Object, Vector<Object>> actions;
+ private int scanPos;
+ private static Material origMat = new Material(null);
+ public static String base64 = "-0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+";
+ private static String[] permittedList = ServerTableManager.instance().getTable("permittedList");
+ private static String[] faceList = ServerTableManager.instance().getTable("faceList");
+ private static String[] humanList = ServerTableManager.instance().getTable("humanList");
+ private static String[] secretList = ServerTableManager.instance().getTable("secretList");
+ private static Hashtable<String, String> permittedHash = new Hashtable<String, String>();
+ private static Vector<String> permittedNames = new Vector<String>();
+ private static Vector<String> faceNames = new Vector<String>();
+ private static Hashtable<String, String> humanHash = new Hashtable<String, String>();
+ private static Hashtable<String, Vector<String>> worldHash = new Hashtable<String, Vector<String>>();
+ private static Hashtable<String, String> secretNames = new Hashtable<String, String>();
+ private static Hashtable<String, String> faceTextures = new Hashtable<String, String>();
+ static boolean gotServerAvatarList;
+ static boolean serverAvatarListError;
+ private Enumeration<String> animations;
+ private boolean doLOD = false;
+ protected int expressionStart;
+ protected int nextChange;
+ protected Vector<PosableShape.TimedMatChange> expressionChanges;
+ private static Object classCookie;
+
+ static {
+ if (!NetUpdate.isInternalVersion()) {
+ for (int i = 0; i < secretList.length; i++) {
+ secretNames.put(secretList[i], secretList[i]);
+ }
+ }
+
+ for (int i = 0; i < permittedList.length; i += 2) {
+ if (secretNames.get(permittedList[i]) == null) {
+ permittedNames.addElement(permittedList[i]);
+ if (permittedList[i + 1].indexOf("DgT") >= 0) {
+ faceNames.addElement(permittedList[i]);
+ }
+ }
+
+ if (permittedList[i + 1] != null) {
+ permittedHash.put(permittedList[i], permittedList[i + 1]);
+ }
+ }
+
+ for (int i = 1; i < humanList.length; i += 2) {
+ humanHash.put(humanList[i - 1], humanList[i]);
+ }
+
+ for (int i = 0; i < faceList.length; i += 2) {
+ faceTextures.put(faceList[i], faceList[i + 1]);
+ }
+
+ gotServerAvatarList = false;
+ serverAvatarListError = false;
+ classCookie = new Object();
+ }
+
+ public static URL getDefaultURL() {
+ return defaultURL;
+ }
+
+ public PosableShape(URL url) {
+ this.setURL(url);
+ }
+
+ public PosableShape(URL url, boolean isAW) {
+ this.setPrepFigure = isAW;
+ this.runPrepFigure = this.setPrepFigure;
+ this.setURL(url);
+ }
+
+ public PosableShape() {
+ }
+
+ @Override
+ public void loadInit() {
+ this.setURL(defaultURL);
+ }
+
+ @Override
+ public void markVoid() throws ClassCastException {
+ if (this.animator != null) {
+ this.animator.endanimations();
+ if (this.figureType != -1) {
+ this.animator.delayedDeltype(this.figureType);
+ }
+ }
+
+ this.animator = null;
+ this.getRoom().removePrerenderHandler(this);
+ super.markVoid();
+ }
+
+ @Override
+ public synchronized void recursiveAddRwChildren(WObject parent) {
+ if (!this.hasClump()) {
+ super.recursiveAddRwChildren(parent);
+ this.getRoom().addPrerenderHandler(this);
+ if (this.isFullyLoaded() && this.figureType != -1) {
+ DroneAnimator.addtype(this.figureType);
+ if (this.runPrepFigure) {
+ DroneAnimator.prepFigure(this, this.COG);
+ }
+
+ this.animator = new DroneAnimator();
+ }
+ }
+ }
+
+ @Override
+ public void notifyShapeLoaded(Shape s) {
+ this.recomputeHeight = true;
+ }
+
+ @Override
+ public Transform getObjectToWorldMatrix() {
+ return this.clumpID != 0 ? this.getJointedObjectToWorldMatrix(Transform.make()) : super.getObjectToWorldMatrix();
+ }
+
+ public static int getFigureType(URL url) {
+ String bodyType = getBodyType(url);
+ return bodyType == null ? -1 : DroneAnimator.getnameindex(bodyType);
+ }
+
+ public static int getFigureType(String bodyType) {
+ bodyType = getBodyType(bodyType);
+ return bodyType == null ? -1 : DroneAnimator.getnameindex(bodyType);
+ }
+
+ protected void download(URL pUrl) {
+ PendingDrone pd = PosableDroneLoader.makePendingDrone(null, pUrl);
+ Enumeration<String> e = getComponentAvatars(pd.getUrl());
+ if (e != null) {
+ while (e.hasMoreElements()) {
+ String avURL = e.nextElement();
+ pd.download(URL.make(avURL));
+ }
+ }
+ }
+
+ @Override
+ public synchronized void setURL(URL newName) {
+ if (newName != this.url && (newName == null || !newName.equals(this.url))) {
+ if (newName == null || !newName.toString().startsWith("avatar:lod")) {
+ if (newName != null) {
+ this.download(newName);
+ int newType = getFigureType(newName);
+ if (newType != this.figureType) {
+ if (this.animator != null) {
+ this.animator.endanimations();
+ if (this.figureType != -1) {
+ this.animator.delayedDeltype(this.figureType);
+ }
+ }
+
+ this.animator = null;
+ this.figureType = newType;
+ this.animationList = null;
+ }
+ }
+
+ this.setBaseLODURL(newName);
+ if (forceLODLevel != -1 && this.numDetailLevels > 0 && this.doLOD) {
+ this.setLOD(0.0F);
+ return;
+ }
+ }
+
+ this.removeSubparts();
+ if (newName != null && newName.getAbsolute().startsWith("avatar:")) {
+ try {
+ this.createSubparts(newName);
+ } catch (MalformedURLException var3) {
+ System.out.println("Received bogus PosableShape URL: " + newName);
+ return;
+ }
+ }
+
+ super.setURL(newName);
+ }
+ }
+
+ private String scanName(String s) {
+ int start = this.scanPos;
+
+ char c;
+ while ((c = s.charAt(this.scanPos)) >= 'a' && c <= 'z' || c == '_') {
+ this.scanPos++;
+ }
+
+ return s.substring(start, this.scanPos);
+ }
+
+ public static String readName(String s, int pos) {
+ int start = pos;
+
+ char c;
+ try {
+ while ((c = s.charAt(pos)) >= 'a' && c <= 'z' || c == '_') {
+ pos++;
+ }
+ } catch (StringIndexOutOfBoundsException var4) {
+ }
+
+ return s.substring(start, pos);
+ }
+
+ private int scanInt(String s) {
+ int start = this.scanPos;
+
+ int val;
+ char c;
+ for (val = 0; (c = s.charAt(this.scanPos)) >= '0' && c <= '9'; this.scanPos++) {
+ val = 10 * val + (c - '0');
+ }
+
+ return val;
+ }
+
+ private static Material scanTexture(String name, int frame) {
+ if (frame <= 0) {
+ name = "avatar:" + name + ".cmp";
+ } else {
+ name = "avatar:" + name + frame + "s*.mov";
+ }
+
+ Material m = new Material(0.32F, 0.55F, 0.0F, colorTable[3], null, 1.0F, true, false);
+ m.loadTexture(URL.make(name));
+ return m;
+ }
+
+ public static Material readTexture(String s, int p) {
+ int frame = 0;
+
+ char c;
+ while ((c = s.charAt(p)) >= '0' && c <= '9') {
+ frame = 10 * frame + (c - '0');
+ p++;
+ }
+
+ return scanTexture(readName(s, p), frame);
+ }
+
+ public static boolean isValidTexture(String s) {
+ int len = s.length();
+ int i = 0;
+
+ char c;
+ while (i < len && (c = s.charAt(i)) >= '0' && c <= '9') {
+ i++;
+ }
+
+ while (i < len) {
+ if (((c = s.charAt(i)) < 'a' || c > 'z') && c != '_') {
+ return false;
+ }
+
+ i++;
+ }
+
+ return true;
+ }
+
+ private static int scanBase64(char c) {
+ int i = base64.indexOf(c);
+ return i < 0 ? 0 : i;
+ }
+
+ public static Material readColor(String s, int p) {
+ char c = s.charAt(p++);
+ Material m = null;
+ if (c == '_') {
+ int color = s.charAt(p++) - 'A';
+ if (color >= 0 && color < colorTable.length) {
+ m = new Material(0.32F, 0.55F, 0.0F, colorTable[color], null, 1.0F, true, false);
+ } else {
+ m = origMat;
+ }
+ } else {
+ int r = 4 * scanBase64(c);
+ int g = 4 * scanBase64(s.charAt(p++));
+ int b = 4 * scanBase64(s.charAt(p++));
+ m = new Material(0.32F, 0.55F, 0.0F, new Color(r, g, b), null, 1.0F, true, false);
+ }
+
+ return m;
+ }
+
+ private Material scanColor(String s) {
+ Material m = readColor(s, this.scanPos);
+ if (s.charAt(this.scanPos) == '_') {
+ this.scanPos += 2;
+ } else {
+ this.scanPos += 3;
+ }
+
+ return m;
+ }
+
+ private float getScale(char c) {
+ if (c >= 'a' && c <= 'z') {
+ return 1.0F - (c - 'a' + 1) * 0.025615385F;
+ } else {
+ return c >= 'A' && c <= 'Z' ? 1.0F / (1.0F - (c - 'A' + 1) * 0.025615385F) : 1.0F;
+ }
+ }
+
+ private Material getMat(char c, Vector<Material> mats) {
+ int matNum = c - 'a';
+ if (matNum < mats.size()) {
+ Material m = mats.elementAt(matNum);
+ return m == origMat ? origMat : (Material)m.clone();
+ } else {
+ return null;
+ }
+ }
+
+ private Shape getLimb(String s, String bodyType, int pos, int partNum, Shape parent, Vector<Material> mats, boolean loadNow) {
+ int end = s.length() - 4;
+ if (bodyType == null) {
+ if (parent instanceof PosableShape) {
+ bodyType = "";
+ } else {
+ bodyType = Shape.getBodBase(parent.getURL());
+ if (parent.getURL().toString().indexOf("lod/") != -1) {
+ bodyType = "lod/" + bodyType;
+ }
+ }
+ }
+
+ Shape shape = new Shape();
+ Shape subshape = shape;
+ shape.setURL(URL.make("avatar:" + bodyType + partNum / 10 + partNum % 10 + ".bod"));
+ int clumpsUsed = 0;
+ Material lastMat = null;
+ int delay = 0;
+ int lastTime = 0;
+ String actName = null;
+ boolean haveAddedChange = false;
+ if (pos > 0) {
+ this.scanPos = pos + 1;
+
+ while (true) {
+ char c = s.charAt(this.scanPos++);
+ if (c >= 'A' && c <= 'Z') {
+ if (c == 'G') {
+ int num = this.scanInt(s);
+ if (num <= 0 || num > 99) {
+ num = partNum;
+ }
+
+ bodyType = this.scanName(s);
+ if (bodyType.equals("")) {
+ break;
+ }
+
+ subshape.setURL(URL.make("avatar:" + bodyType + num / 10 + num % 10 + ".bod"));
+ } else if (c == 'S') {
+ char xScale = s.charAt(this.scanPos++);
+ char yScale = s.charAt(this.scanPos++);
+ char zScale = s.charAt(this.scanPos++);
+ if (xScale == 'Z' && yScale == 'Z' && zScale == 'Z') {
+ this.runPrepFigure = false;
+ }
+
+ subshape.scale(this.getScale(xScale), this.getScale(yScale), this.getScale(zScale));
+ } else if (c != 'Q') {
+ if (c == 'C') {
+ assert false;
+ } else if (c == 'D') {
+ delay += (int)(1000.0 * (Math.pow(1.0932, scanBase64(s.charAt(this.scanPos++))) - 0.9F));
+ } else if (c == 'A') {
+ actName = this.scanName(s);
+ this.animationList = null;
+ } else {
+ if (c != 'T' && c != 'C') {
+ this.scanPos--;
+ break;
+ }
+
+ System.out.println("Illegal av " + this.url);
+ }
+ }
+ } else if (c >= 'a') {
+ Material m = this.getMat(c, mats);
+ if (m != null) {
+ if (delay == 0) {
+ delay = 50;
+ }
+
+ lastTime += delay;
+ if (lastMat != null) {
+ if (!haveAddedChange) {
+ haveAddedChange = true;
+ this.addChange(lastTime - delay, lastMat, subshape);
+ }
+
+ this.addChange(lastTime, m, subshape);
+ }
+
+ if (m != origMat) {
+ subshape.setMaterial(m);
+ }
+
+ lastMat = m;
+ delay = 0;
+ }
+ } else {
+ if (c < '0' || c > '9') {
+ break;
+ }
+
+ this.scanPos--;
+ int clumpNum = this.scanInt(s) - clumpsUsed;
+ clumpsUsed++;
+ subshape = new SubclumpShape();
+ subshape.setURL(URL.make("system:subclump" + clumpNum));
+ shape.add(subshape);
+ lastMat = null;
+ haveAddedChange = false;
+ lastTime = 0;
+ delay = 0;
+ }
+
+ if (this.scanPos > end) {
+ this.scanPos = end;
+ return parent;
+ }
+ }
+ }
+
+ if (bodyType.equals("")) {
+ return parent;
+ } else {
+ shape.addLoadListener(this);
+ if (ProgressiveAdder.get().enabled() && !loadNow) {
+ ProgressiveAdder.get().scheduleForAdd(parent, shape);
+ } else {
+ parent.add(shape);
+ }
+
+ if (this.subparts == null) {
+ this.subparts = shape;
+ }
+
+ return shape;
+ }
+ }
+
+ private void addChange(int when, Material mat, Shape s) {
+ PosableShape.TimedMatChange t = new PosableShape.TimedMatChange();
+ t.when = when;
+ t.mat = mat;
+ t.limb = s;
+ mat.setKeepLoaded(true);
+ int i = 0;
+ if (this.expressionChanges == null) {
+ this.expressionChanges = new Vector<PosableShape.TimedMatChange>();
+ this.expressionStart = Std.getRealTime();
+ this.nextChange = 0;
+ } else {
+ for (i = this.expressionChanges.size(); i > 0; i--) {
+ PosableShape.TimedMatChange o = this.expressionChanges.elementAt(i - 1);
+ if (when >= o.when) {
+ break;
+ }
+ }
+ }
+
+ this.expressionChanges.insertElementAt(t, i);
+ }
+
+ public static Enumeration<String> getComponentAvatars(URL pUrl) {
+ if (pUrl == null) {
+ return null;
+ } else {
+ Vector<String> v = new Vector<String>();
+ String urlString = pUrl.getAbsolute();
+ if (urlString.startsWith("avatar:") && urlString.endsWith(".rwg")) {
+ String baseAv = urlString.substring(7, urlString.indexOf(46));
+ v.addElement("avatar:" + baseAv + ".rwg");
+ int pos = urlString.indexOf(46);
+ int len = urlString.length() - 4;
+
+ label82:
+ while (pos < len) {
+ char c = urlString.charAt(pos++);
+ if (c >= 'A' && c <= 'Z') {
+ switch (c) {
+ case 'A':
+ case 'Q':
+ case 'T':
+ default:
+ break;
+ case 'C':
+ c = urlString.charAt(pos++);
+ if (c == '_') {
+ pos++;
+ } else {
+ pos += 2;
+ }
+ break;
+ case 'D':
+ pos++;
+ break;
+ case 'G':
+ while (pos < len) {
+ c = urlString.charAt(pos);
+ if (c < '0' || c > '9') {
+ break;
+ }
+
+ pos++;
+ }
+
+ String bodyType = "";
+
+ while (true) {
+ if (pos < len) {
+ c = urlString.charAt(pos);
+ if ((c < '0' || c > '9') && c >= 'a' && c <= 'z') {
+ bodyType = bodyType + c;
+ pos++;
+ continue;
+ }
+ }
+
+ if (bodyType != "" && bodyType.length() > 1) {
+ v.addElement("avatar:" + bodyType + ".rwg");
+ }
+ continue label82;
+ }
+ case 'S':
+ pos += 3;
+ }
+ }
+ }
+
+ return v.elements();
+ } else {
+ return null;
+ }
+ }
+ }
+
+ public static int skipLimb(String s, int pos) {
+ int len = s.length() - 4;
+
+ while (pos < len) {
+ char c = s.charAt(pos++);
+ if (c >= 'A' && c <= 'Z') {
+ switch (c) {
+ case 'A':
+ case 'G':
+ case 'Q':
+ case 'T':
+ break;
+ case 'C':
+ c = s.charAt(pos++);
+ if (c == '_') {
+ pos++;
+ } else {
+ pos += 2;
+ }
+ break;
+ case 'D':
+ pos++;
+ break;
+ case 'S':
+ pos += 3;
+ break;
+ default:
+ return pos - 1;
+ }
+ } else if ((c < 'a' || c > 'z') && (c < '0' || c > '9')) {
+ break;
+ }
+ }
+
+ return -1;
+ }
+
+ private String findStarts(String s, int end, int[] offs, String bodyType, Vector<Material> mats) {
+ String lastTextureName = bodyType;
+
+ while (this.scanPos < end) {
+ char section = s.charAt(this.scanPos);
+ if (section < 'A' || section > 'Z') {
+ return s;
+ }
+
+ offs[section - 'A'] = this.scanPos++;
+
+ while (this.scanPos < end) {
+ char c = s.charAt(this.scanPos++);
+ if (c < 'A' || c > 'Z') {
+ if ((c < '0' || c > '9') && (c < 'a' || c > 'z')) {
+ return s.substring(0, this.scanPos - 1) + ".rwg";
+ }
+ } else if (c == 'G') {
+ this.scanInt(s);
+ this.scanName(s);
+ } else if (c == 'S') {
+ this.scanPos += 3;
+ } else if (c != 'Q') {
+ if (c == 'C' || c == 'T') {
+ int start = this.scanPos - 1;
+ char letter = (char)(97 + mats.size());
+ Material mat;
+ if (c == 'C') {
+ mat = this.scanColor(s);
+ } else {
+ int num = this.scanInt(s);
+ String name = this.scanName(s);
+ if (name.equals("")) {
+ name = lastTextureName;
+ } else {
+ lastTextureName = name;
+ }
+
+ mat = scanTexture(name, num);
+ }
+
+ mats.addElement(mat);
+ s = s.substring(0, start) + 'Q' + letter + s.substring(this.scanPos);
+ int cutLen = this.scanPos - start - 2;
+ this.scanPos -= cutLen;
+ end -= cutLen;
+ } else if (c == 'D') {
+ this.scanPos++;
+ } else {
+ if (c != 'A') {
+ this.scanPos--;
+ break;
+ }
+
+ this.scanName(s);
+ }
+ }
+ }
+ }
+
+ return s;
+ }
+
+ public static Vector<String> getPermittedNames() {
+ return permittedNames;
+ }
+
+ public static String[] getPermittedList() {
+ return permittedList;
+ }
+
+ public static void downloadPermittedNames() {
+ if (!gotServerAvatarList) {
+ serverAvatarListError = false;
+ WorldServer w = Pilot.getActive().getServer();
+ if (w != null && w.getGalaxy() != null) {
+ String avatarList = Console.getActive().getScriptServer() + "getavlist.pl?u=" + w.getGalaxy().getChatname();
+ if (w.getGalaxy().getSerialNum() != null) {
+ avatarList = avatarList + "&s=" + w.getGalaxy().getSerialNum();
+ }
+
+ URL avatarListURL = URL.make(avatarList);
+ CacheFile cf = Cache.getFile(avatarListURL, true);
+ cf.waitUntilLoaded();
+ if (!cf.error()) {
+ permittedNames.removeAllElements();
+ humanHash.clear();
+ worldHash.clear();
+
+ try {
+ RandomAccessFile f = new RandomAccessFile(cf.getLocalName(), "r");
+
+ while (f.getFilePointer() < f.length()) {
+ String line = f.readLine();
+ if (!line.startsWith("//")) {
+ StringTokenizer st = new StringTokenizer(line);
+ if (st.countTokens() > 2) {
+ String name = st.nextToken();
+ permittedNames.addElement(name);
+ String gender = st.nextToken();
+ if (gender.equals("m") || gender.equals("f")) {
+ humanHash.put(name, gender);
+ }
+
+ Vector<String> worldList = new Vector<String>();
+
+ while (st.hasMoreTokens()) {
+ worldList.addElement(st.nextToken());
+ }
+
+ worldHash.put(name, worldList);
+ }
+ }
+ }
+
+ f.close();
+ } catch (Exception var10) {
+ System.out.println("Error parsing avatar list: " + var10.toString());
+ serverAvatarListError = true;
+ return;
+ }
+
+ gotServerAvatarList = true;
+ Console c = Console.getActive();
+ if (c instanceof DefaultConsole) {
+ DefaultConsole dc = (DefaultConsole)c;
+ dc.getAvatarMenu().rebuildVIPMenu();
+ }
+
+ if (c.getPilot() != null) {
+ c.getPilot().resetAvatarNow();
+ }
+
+ AvMenu.rebuildHeadList();
+ } else {
+ serverAvatarListError = true;
+ }
+ }
+ }
+ }
+
+ public static URL getPermitted(URL in, World world) {
+ if (in.endsWith(".mov")) {
+ return in;
+ } else if (NetUpdate.isInternalVersion()) {
+ return in;
+ } else if (!gotServerAvatarList && !serverAvatarListError) {
+ return in;
+ } else if (serverAvatarListError) {
+ return validateAvatar(in.getAbsolute()) ? in : getDefAv();
+ } else {
+ Enumeration<String> e = getComponentAvatars(in);
+
+ while (e != null && e.hasMoreElements()) {
+ String baseAv = e.nextElement();
+ String s = getBodyType(URL.make(baseAv));
+ if (s == null) {
+ return getDefAv();
+ }
+
+ Vector<String> allowedWorlds = worldHash.get(s);
+ if (allowedWorlds == null) {
+ return getDefAv();
+ }
+
+ boolean worldOK = false;
+ Enumeration<String> we = allowedWorlds.elements();
+
+ while (true) {
+ if (we.hasMoreElements()) {
+ String thisWorld = we.nextElement();
+ if (thisWorld == null) {
+ return getDefAv();
+ }
+
+ if (thisWorld.equals("all")) {
+ worldOK = true;
+ } else {
+ thisWorld = thisWorld.replace('_', ' ').toLowerCase().trim();
+ if (world == null) {
+ worldOK = true;
+ continue;
+ }
+
+ if (!thisWorld.equals(world.toString().toLowerCase().trim())) {
+ continue;
+ }
+
+ worldOK = true;
+ }
+ }
+
+ if (!worldOK) {
+ return getDefAv();
+ }
+ break;
+ }
+ }
+
+ return in;
+ }
+ }
+
+ public static Vector<String> getFaceNames() {
+ return faceNames;
+ }
+
+ public static URL getAvURL(String bodyType) {
+ Object newName = permittedHash.get(bodyType);
+ return newName instanceof String ? URL.make("avatar:" + (String)newName) : null;
+ }
+
+ public static boolean validateAvatar(String av) {
+ System.out.println("Validating " + av);
+ String baseAv = getBodyType(URL.make(av));
+ return baseAv == null ? false : permittedHash.get(baseAv) != null;
+ }
+
+ public static String convertLODToParent(String bodyType) {
+ String result = bodyType;
+ if (bodyType.startsWith("lod/")) {
+ result = bodyType.substring(4, bodyType.length() - 1);
+ }
+
+ return result;
+ }
+
+ public static String getBodyType(URL url) {
+ if (url == null) {
+ return null;
+ } else {
+ String str = url.getAbsolute();
+ if (str.startsWith("avatar:") && (str.endsWith(".rwg") || str.endsWith(".RWG")) && str.charAt(7) != '.') {
+ int pos = str.indexOf(".", 7);
+ String bodyType = str.substring(7, pos).toLowerCase();
+ bodyType = convertLODToParent(bodyType);
+ if (str.charAt(pos + 1) != '0') {
+ bodyType = getBodyType(bodyType);
+ }
+
+ return bodyType;
+ } else {
+ return null;
+ }
+ }
+ }
+
+ static URL getDefAv() {
+ return URL.make(IniFile.override().getIniString("DefaultArticAv", "avatar:willy.rwg"));
+ }
+
+ public static URL getHuman(URL url) {
+ if (url.endsWith(".mov")) {
+ return HoloDrone.getHuman(url);
+ } else {
+ String s = getBodyType(url);
+ if (s == null) {
+ return getDefAv();
+ } else {
+ String gender = humanHash.get(s);
+ if (gender == null) {
+ return getDefAv();
+ } else {
+ URL def = URL.make("avatar:" + s + ".rwg");
+ String str = url.getAbsolute();
+ int pos = str.indexOf(".0EC_");
+ if (pos >= 0 && str.length() >= pos + 7 && "_AC".indexOf(str.charAt(pos + 5)) >= 0) {
+ if (!gender.equals("m")
+ || str.indexOf("yank") < 0
+ || str.regionMatches(pos + 6, "TyankshirtC_", 0, 12) && str.regionMatches(pos + 19, "C-2bTyankstripe", 0, 15)) {
+ pos = str.lastIndexOf("HDgT2");
+ if (pos >= 0 && str.length() >= pos + 7) {
+ String faceGender = humanHash.get(readName(str, pos + 5));
+ if (faceGender != null && faceGender.equals(gender)) {
+ pos = str.lastIndexOf("NS");
+ if (pos >= 0 && str.length() >= pos + 3 && "0abcdABCD".indexOf(str.charAt(pos + 2)) >= 0) {
+ pos += 5;
+ if (str.length() < pos + 2) {
+ return def;
+ } else {
+ if (str.charAt(pos) == 'G') {
+ String headGender = humanHash.get(readName(str, pos + 1));
+ if (headGender == null || !headGender.equals(gender)) {
+ return def;
+ }
+ }
+
+ return url;
+ }
+ } else {
+ return def;
+ }
+ } else {
+ return def;
+ }
+ } else {
+ return def;
+ }
+ } else {
+ return def;
+ }
+ } else {
+ return def;
+ }
+ }
+ }
+ }
+ }
+
+ public URL getHuman() {
+ return getHuman(this.getURL());
+ }
+
+ public static String getBodyType(String basename) {
+ String str = permittedHash.get(basename);
+ if (str != null) {
+ basename = str.substring(0, str.indexOf("."));
+ }
+
+ return basename;
+ }
+
+ public static int getMatPosition(String str, char type) {
+ int index = "abcdef".indexOf(type);
+ if (index >= 0) {
+ int p = str.indexOf(".0E");
+ if (p >= 0) {
+ p += 3;
+
+ for (int i = 0; i < index; i++) {
+ p = skipMat(str, p);
+ }
+ }
+
+ return p;
+ } else {
+ int p = str.indexOf(".0E");
+ if (p >= 0) {
+ for (p += 2; p >= 0; p = skipLimb(str, p)) {
+ if (str.charAt(p++) == type) {
+ return p;
+ }
+ }
+ }
+
+ return p;
+ }
+ }
+
+ public static String getCurrentAvCustomizable() {
+ URL av = Pilot.getActive().getSourceURL();
+ String str = av.getAbsolute();
+ if (str.startsWith("avatar:") && (str.endsWith(".rwg") || str.endsWith(".RWG")) && str.charAt(7) != '.') {
+ int pos = str.indexOf(".", 7);
+ if (!str.regionMatches(pos, ".0E", 0, 3)) {
+ av = getAvURL(str.substring(7, pos).toLowerCase());
+ if (av == null) {
+ if (!str.substring(pos).equalsIgnoreCase(".rwg")) {
+ Console.println(Console.message("cant-cust-av"));
+ return null;
+ }
+
+ str = "avatar:" + str.substring(7, pos) + ".0EC__C__C__C__C__C__" + "PeBbLcMcOaRcUcVaWeXeYIeJeK" + "NS000QaHDgT2tonyT3T2T1Q0f.rwg";
+ } else {
+ str = av.getAbsolute();
+ }
+ }
+
+ return str;
+ } else {
+ Console.println(Console.message("non-cust-av"));
+ return null;
+ }
+ }
+
+ public static int skipMat(String s, int i) {
+ char c = s.charAt(i);
+ int matEnd = i;
+ if (c == 'C') {
+ c = s.charAt(i + 1);
+ if (c == '_') {
+ matEnd = i + 3;
+ } else {
+ matEnd = i + 4;
+ }
+ } else if (c == 'T') {
+ matEnd = i + 1;
+
+ while ((c = s.charAt(matEnd)) >= '0' && c <= '9') {
+ matEnd++;
+ }
+
+ while ((c = s.charAt(matEnd)) >= 'a' && c <= 'z') {
+ matEnd++;
+ }
+ } else if (c >= 'a' && c <= 'z') {
+ matEnd = i + 1;
+ }
+
+ return matEnd;
+ }
+
+ public static String getFace(String bodyType) {
+ Object face = faceTextures.get(bodyType);
+ return face != null ? (String)face : "1" + bodyType;
+ }
+
+ private void createSubparts(URL url) throws MalformedURLException {
+ String str = url.getAbsolute();
+ int len = str.length();
+ String bodyType = null;
+ this.runPrepFigure = this.setPrepFigure;
+ if (str.startsWith("avatar:") && (str.endsWith(".rwg") || str.endsWith(".RWG")) && str.charAt(7) != '.') {
+ this.scanPos = str.indexOf(".", 7);
+ bodyType = str.substring(7, this.scanPos).toLowerCase();
+ if (str.charAt(this.scanPos + 1) != '0') {
+ this.scanPos = len - 4;
+ Object newName = permittedHash.get(bodyType);
+ if (newName != null) {
+ str = (String)newName;
+ this.scanPos = 0;
+ bodyType = this.scanName(str);
+ if (str.charAt(this.scanPos) != '.') {
+ throw new MalformedURLException();
+ }
+
+ if (str.charAt(this.scanPos + 1) != '0') {
+ throw new MalformedURLException();
+ }
+
+ this.scanPos += 2;
+ }
+ } else {
+ this.scanPos += 2;
+ }
+ } else {
+ this.scanPos = 0;
+ str = ".rwg";
+ bodyType = "aura";
+ }
+
+ Vector<Material> mats = new Vector<Material>();
+ int[] offsets = new int[26];
+ str = this.findStarts(str, str.length() - 4, offsets, bodyType, mats);
+ if (this.subparts != null) {
+ throw new MalformedURLException();
+ } else {
+ Shape groi = this.getLimb(str, bodyType, offsets[15], 1, this, mats, true);
+ Shape back = this.getLimb(str, null, offsets[1], 2, groi, mats, false);
+ Shape neck = this.getLimb(str, null, offsets[13], 3, back, mats, false);
+ Shape head = this.getLimb(str, null, offsets[7], 4, neck, mats, false);
+ Shape lupa = this.getLimb(str, null, offsets[11], 11, back, mats, false);
+ Shape lfor = this.getLimb(str, null, offsets[12], 12, lupa, mats, false);
+ Shape lhan = this.getLimb(str, null, offsets[14], 13, lfor, mats, false);
+ Shape rupa = this.getLimb(str, null, offsets[17], 6, back, mats, false);
+ Shape rfor = this.getLimb(str, null, offsets[20], 7, rupa, mats, false);
+ Shape rhan = this.getLimb(str, null, offsets[21], 8, rfor, mats, false);
+ Shape lthi = this.getLimb(str, null, offsets[8], 19, groi, mats, false);
+ Shape lcal = this.getLimb(str, null, offsets[9], 20, lthi, mats, false);
+ Shape lfoo = this.getLimb(str, null, offsets[10], 21, lcal, mats, false);
+ Shape rthi = this.getLimb(str, null, offsets[22], 15, groi, mats, false);
+ Shape rcal = this.getLimb(str, null, offsets[23], 16, rthi, mats, false);
+ Shape rfoo = this.getLimb(str, null, offsets[24], 17, rcal, mats, false);
+ Shape tail = this.getLimb(str, null, offsets[25], 24, groi, mats, false);
+ }
+ }
+
+ protected void removeSubparts() {
+ if (this.subparts != null) {
+ this.subparts.discard();
+ this.subparts = null;
+ this.actions = null;
+ }
+ }
+
+ @Override
+ public void prerender(Camera cam) {
+ if (this.getVisible()) {
+ Point3Temp p = this.inCamSpace(cam);
+ boolean v = p != null && p.z > 1.0F && p.x < p.z && -p.x < p.z;
+ if (v) {
+ if (this.closestView > p.z) {
+ this.closestView = p.z;
+ }
+
+ if (p.z > 700.0F && ++this.farViewCount > 10) {
+ if (this.closestView > 400.0F) {
+ this.closestView = 400.0F;
+ }
+
+ this.farViewCount = 0;
+ }
+ }
+ }
+ }
+
+ public float animate(String action) {
+ if (this.animator == null) {
+ return 0.0F;
+ } else {
+ if (action.length() == 1) {
+ char lower = action.toLowerCase().charAt(0);
+ char upper = action.toUpperCase().charAt(0);
+ Vector<String> al = this.getAnimationList();
+ int len = al.size();
+
+ for (int i = 0; i < len; i++) {
+ String[] actionAliases = ServerTableManager.instance().getTable("actionAliases");
+ String displayName = al.elementAt(i);
+ if (actionAliases != null) {
+ for (int j = 0; j < actionAliases.length; j += 2) {
+ if (displayName.toLowerCase().equals(actionAliases[j].toLowerCase())) {
+ displayName = actionAliases[j + 1];
+ break;
+ }
+ }
+ }
+
+ char c = displayName.charAt(0);
+ if (c == lower || c == upper) {
+ action = al.elementAt(i);
+ break;
+ }
+ }
+ }
+
+ return this.performAnimationSequence(action);
+ }
+ }
+
+ @Override
+ public void timerDone() {
+ if (this.animations.hasMoreElements()) {
+ String nextAnim = this.animations.nextElement();
+ float time = this.animator.getAnimationTime(this.figureType, nextAnim);
+ this.animator.animate(this.figureType, nextAnim, Std.getRealTime());
+ Timer tm = new Timer(time, this);
+ tm.start();
+ }
+ }
+
+ private float performAnimationSequence(String action) {
+ float totalTime = 0.0F;
+ Vector<String> vanimations = new Vector<String>();
+ StringTokenizer tok = new StringTokenizer(action, "&\t\n\r");
+
+ while (tok.hasMoreTokens()) {
+ String subAction = tok.nextToken();
+ totalTime += this.animator.getAnimationTime(this.figureType, subAction);
+ vanimations.addElement(subAction);
+ }
+
+ this.animations = vanimations.elements();
+ this.timerDone();
+ return totalTime;
+ }
+
+ public Vector<String> getAnimationList() {
+ if (this.animationList != null) {
+ return this.animationList;
+ } else {
+ this.animationList = DroneAnimator.getActionList(this.figureType);
+ return this.animationList;
+ }
+ }
+
+ public void enableLOD(boolean flag) {
+ this.doLOD = flag;
+ }
+
+ @Override
+ public boolean handle(MouseDownEvent e) {
+ return false;
+ }
+
+ @Override
+ public boolean handle(FrameEvent fe) {
+ float dist = this.closestView;
+ this.closestView = 10000.0F;
+ if (this.animator != null && !(dist > 900.0F) && this.hasClump()) {
+ if (this.recomputeHeight) {
+ if (this.runPrepFigure) {
+ DroneAnimator.prepFigure(this, this.COG);
+ }
+
+ this.recomputeHeight = false;
+ }
+
+ if (this.doLOD && this.setLOD(dist)) {
+ return true;
+ } else {
+ int time = Std.getRealTime();
+ Transform t = this.getObjectToWorldMatrix();
+ this.animator.moveto(this.figureType, (short)t.getX(), (short)t.getY(), (short)t.getZ(), (short)(-t.getYaw()), time - 1);
+ this.animator.update(null, this, time, t.getScaleX(), dist > 700.0F);
+ t.recycle();
+ if (this.expressionStart > 0) {
+ time -= this.expressionStart;
+
+ while (true) {
+ PosableShape.TimedMatChange tx = this.expressionChanges.elementAt(this.nextChange);
+ if (time < tx.when) {
+ break;
+ }
+
+ if (tx.mat != origMat) {
+ tx.limb.setMaterial(tx.mat);
+ }
+
+ if (++this.nextChange >= this.expressionChanges.size()) {
+ this.nextChange = 0;
+ this.expressionStart += time;
+ break;
+ }
+ }
+ }
+
+ return true;
+ }
+ } else {
+ return true;
+ }
+ }
+
+ @Override
+ public Object properties(int index, int offset, int mode, Object value) throws NoSuchPropertyException {
+ Object ret = null;
+ switch (index - offset) {
+ case 0:
+ if (mode == 0) {
+ ret = BooleanPropertyEditor.make(new Property(this, index, "Center of Gravity"), "No", "Yes");
+ } else if (mode == 1) {
+ ret = new Boolean(this.COG);
+ } else if (mode == 2) {
+ this.COG = (Boolean)value;
+ URL u = this.getURL();
+ this.setURL(defaultURL);
+ this.setURL(u);
+ }
+ break;
+ default:
+ ret = super.properties(index, offset + 1, mode, value);
+ }
+
+ return ret;
+ }
+
+ @Override
+ public void saveState(Saver s) throws IOException {
+ s.saveVersion(1, classCookie);
+ s.saveBoolean(this.COG);
+ if (this.subparts != null) {
+ this.subparts.detach();
+ super.saveState(s);
+ this.add(this.subparts);
+ } else {
+ super.saveState(s);
+ }
+ }
+
+ @Override
+ public void restoreState(Restorer r) throws IOException, TooNewException {
+ switch (r.restoreVersion(classCookie)) {
+ case 1:
+ this.COG = r.restoreBoolean();
+ case 0:
+ super.restoreState(r);
+ return;
+ default:
+ throw new TooNewException();
+ }
+ }
+
+ @Override
+ public String toString() {
+ return this.getName();
+ }
+
+ class TimedMatChange {
+ Shape limb;
+ Material mat;
+ int when;
+ }
+}