public static bool modelTypeCached(this GameObjectDefinition definition, int modelType) { if (definition.modelTypes == null) { if (definition.modelIds == null) { return(true); } if (modelType != 10) { return(true); } bool cached = true; for (int id = 0; id < definition.modelIds.Length; id++) { cached &= Model.isCached(definition.modelIds[id] & 0xffff); } return(cached); } for (int type = 0; type < definition.modelTypes.Length; type++) { if (definition.modelTypes[type] == modelType) { return(Model.isCached(definition.modelIds[type] & 0xffff)); } } return(true); }
public static Model getModelAt(this GameObjectDefinition definition, int i, int j, int k, int l, int i1, int j1, int k1) { Model model = definition.getAnimatedModel(i, k1, j); if (model == null) { return(null); } if (definition.adjustToTerrain || definition.delayShading) { model = new Model(definition.adjustToTerrain, definition.delayShading, model); } if (definition.adjustToTerrain) { int l1 = (k + l + i1 + j1) / 4; for (int v = 0; v < model.vertexCount; v++) { int x = model.verticesX[v]; int z = model.verticesZ[v]; int l2 = k + ((l - k) * (x + 64)) / 128; int i3 = j1 + ((i1 - j1) * (x + 64)) / 128; int j3 = l2 + ((i3 - l2) * (z + 64)) / 128; model.verticesY[v] += j3 - l1; } model.normalise(); } return(model); }
public static void passivelyRequestModels(this GameObjectDefinition definition, OnDemandFetcher requester) { if (definition.modelIds == null) { return; } for (int modelId = 0; modelId < definition.modelIds.Length; modelId++) { requester.passiveRequest(definition.modelIds[modelId] & 0xffff, 0); } }
public static bool modelCached(this GameObjectDefinition definition) { if (definition.modelIds == null) { return(true); } bool cached = true; for (int m = 0; m < definition.modelIds.Length; m++) { cached &= Model.isCached(definition.modelIds[m] & 0xffff); } return(cached); }
public static GameObjectDefinition getDefinition(int objectId) { for (int c = 0; c < 20; c++) { if (cache[c].id == objectId) { return(cache[c]); } } cacheIndex = (cacheIndex + 1) % 20; GameObjectDefinition definition = cache[cacheIndex]; stream.position = streamOffsets[objectId]; definition.id = objectId; definition.setDefaults(); definition.loadDefinition(stream); return(definition); }
public static void load(Archive archive) { GameObjectDefinition.stream = new Default317Buffer(archive.decompressFile("loc.dat")); Default317Buffer indexStream = new Default317Buffer(archive.decompressFile("loc.idx")); int objectCount = indexStream.getUnsignedLEShort(); streamOffsets = new int[objectCount]; int offset = 2; for (int index = 0; index < objectCount; index++) { streamOffsets[index] = offset; offset += indexStream.getUnsignedLEShort(); } cache = new GameObjectDefinition[20]; for (int c = 0; c < 20; c++) { cache[c] = new GameObjectDefinition(); } }
public async Task StartupCoroutine() { if (!wasClientStartupCalled) { wasClientStartupCalled = true; } else { throw new InvalidOperationException($"Failed. Cannot call startup on Client multiple times."); } drawLoadingText(20, "Starting up"); if (clientRunning) { rsAlreadyLoaded = true; return; } clientRunning = true; bool validHost = true; String s = getDocumentBaseHost(); if (s.EndsWith("jagex.com")) { validHost = true; } if (s.EndsWith("runescape.com")) { validHost = true; } if (s.EndsWith("192.168.1.2")) { validHost = true; } if (s.EndsWith("192.168.1.229")) { validHost = true; } if (s.EndsWith("192.168.1.228")) { validHost = true; } if (s.EndsWith("192.168.1.227")) { validHost = true; } if (s.EndsWith("192.168.1.226")) { validHost = true; } if (s.EndsWith("127.0.0.1")) { validHost = true; } if (!validHost) { genericLoadingError = true; return; } if (signlink.cache_dat != null) { for (int i = 0; i < 5; i++) { caches[i] = new FileCache(signlink.cache_dat, signlink.cache_idx[i], i + 1); } } connectServer(); archiveTitle = requestArchive(1, "title screen", "title", expectedCRCs[1], 25); fontSmall = new GameFont("p11_full", archiveTitle, false); fontPlain = new GameFont("p12_full", archiveTitle, false); fontBold = new GameFont("b12_full", archiveTitle, false); drawLogo(); loadTitleScreen(); Archive archiveConfig = requestArchive(2, "config", "config", expectedCRCs[2], 30); Archive archiveTextures = requestArchive(6, "textures", "textures", expectedCRCs[6], 45); //Archive archiveWord = requestArchive(7, "chat system", "wordenc", expectedCRCs[7], 50); Archive archiveSounds = requestArchive(8, "sound effects", "sounds", expectedCRCs[8], 55); tileFlags = new byte[4, 104, 104]; intGroundArray = CollectionUtilities.Create3DJaggedArray <int>(4, 105, 105); worldController = new WorldController(intGroundArray); for (int z = 0; z < 4; z++) { currentCollisionMap[z] = new CollisionMap(); } minimapImage = new Sprite(512, 512); Archive archiveVersions = requestArchive(5, "update list", "versionlist", expectedCRCs[5], 60); drawLoadingText(60, "Connecting to update server"); StartOnDemandFetcher(archiveVersions); Animation.init(onDemandFetcher.getAnimCount()); Model.init(onDemandFetcher.fileCount(0), onDemandFetcher); songChanging = true; onDemandFetcher.request(2, nextSong); while (onDemandFetcher.immediateRequestCount() > 0) { processOnDemandQueue(false); await TaskDelayFactory.Create(1); if (onDemandFetcher.failedRequests > 3) { loadError(); return; } } drawLoadingText(65, "Requesting animations"); int fileRequestCount = onDemandFetcher.fileCount(1); for (int id = 0; id < fileRequestCount; id++) { onDemandFetcher.request(1, id); } if (!await ProcessAnimationsAsync(fileRequestCount)) { return; } drawLoadingText(70, "Requesting models"); fileRequestCount = onDemandFetcher.fileCount(0); for (int id = 0; id < fileRequestCount; id++) { int modelId = onDemandFetcher.getModelId(id); if ((modelId & 1) != 0) { onDemandFetcher.request(0, id); } } fileRequestCount = onDemandFetcher.immediateRequestCount(); while (onDemandFetcher.immediateRequestCount() > 0) { int remaining = fileRequestCount - onDemandFetcher.immediateRequestCount(); if (remaining > 0) { drawLoadingText(70, "Loading models - " + (remaining * 100) / fileRequestCount + "%"); } processOnDemandQueue(); await TaskDelayFactory.Create(1); } if (caches[0] != null) { drawLoadingText(75, "Requesting maps"); onDemandFetcher.request(3, onDemandFetcher.getMapId(0, 47, 48)); onDemandFetcher.request(3, onDemandFetcher.getMapId(1, 47, 48)); onDemandFetcher.request(3, onDemandFetcher.getMapId(0, 48, 48)); onDemandFetcher.request(3, onDemandFetcher.getMapId(1, 48, 48)); onDemandFetcher.request(3, onDemandFetcher.getMapId(0, 49, 48)); onDemandFetcher.request(3, onDemandFetcher.getMapId(1, 49, 48)); onDemandFetcher.request(3, onDemandFetcher.getMapId(0, 47, 47)); onDemandFetcher.request(3, onDemandFetcher.getMapId(1, 47, 47)); onDemandFetcher.request(3, onDemandFetcher.getMapId(0, 48, 47)); onDemandFetcher.request(3, onDemandFetcher.getMapId(1, 48, 47)); onDemandFetcher.request(3, onDemandFetcher.getMapId(0, 48, 148)); onDemandFetcher.request(3, onDemandFetcher.getMapId(1, 48, 148)); fileRequestCount = onDemandFetcher.immediateRequestCount(); while (onDemandFetcher.immediateRequestCount() > 0) { int remaining = fileRequestCount - onDemandFetcher.immediateRequestCount(); if (remaining > 0) { drawLoadingText(75, "Loading maps - " + (remaining * 100) / fileRequestCount + "%"); } processOnDemandQueue(false); await TaskDelayFactory.Create(1); } } fileRequestCount = onDemandFetcher.fileCount(0); for (int id = 0; id < fileRequestCount; id++) { int modelId = onDemandFetcher.getModelId(id); byte priority = 0; if ((modelId & 8) != 0) { priority = 10; } else if ((modelId & 0x20) != 0) { priority = 9; } else if ((modelId & 0x10) != 0) { priority = 8; } else if ((modelId & 0x40) != 0) { priority = 7; } else if ((modelId & 0x80) != 0) { priority = 6; } else if ((modelId & 2) != 0) { priority = 5; } else if ((modelId & 4) != 0) { priority = 4; } if ((modelId & 1) != 0) { priority = 3; } if (priority != 0) { onDemandFetcher.setPriority(priority, 0, id); } } //Don't need to even preload. await((WebGLOnDemandFetcher)onDemandFetcher).preloadRegionsAsync(membersWorld); //Remove low memory check. int count = onDemandFetcher.fileCount(2); for (int id = 1; id < count; id++) { if (onDemandFetcher.midiIdEqualsOne(id)) { onDemandFetcher.setPriority((byte)1, 2, id); } } //We don't unpack media here on WebGL because it //causes memory problems. drawLoadingText(83, "Unpacking textures"); Rasterizer.unpackTextures(archiveTextures); Rasterizer.calculatePalette(0.80000000000000004D); Rasterizer.resetTextures(); drawLoadingText(86, "Unpacking config"); AnimationSequence.unpackConfig(archiveConfig); GameObjectDefinition.load(archiveConfig); FloorDefinition.load(archiveConfig); ItemDefinition.load(archiveConfig); EntityDefinition.load(archiveConfig); IdentityKit.load(archiveConfig); SpotAnimation.load(archiveConfig); Varp.load(archiveConfig); VarBit.load(archiveConfig); ItemDefinition.membersWorld = membersWorld; //Removed low memory check drawLoadingText(90, "Unpacking sounds"); //Sound loading disabled in WebGL. byte[] soundData = archiveSounds.decompressFile("sounds.dat"); Effect.load(new Default317Buffer(soundData)); }
public static Model getAnimatedModel(this GameObjectDefinition definition, int type, int animationId, int face) { Model subModel = null; long hash; if (definition.modelTypes == null) { if (type != 10) { return(null); } hash = (definition.id << 6) + face + ((long)(animationId + 1) << 32); Model cachedModel = (Model)GameObjectDefinition.animatedModelCache.get(hash); if (cachedModel != null) { return(cachedModel); } if (definition.modelIds == null) { return(null); } bool mirror = definition.rotated ^ (face > 3); int modelCount = definition.modelIds.Length; for (int m = 0; m < modelCount; m++) { int subModelId = definition.modelIds[m]; if (mirror) { subModelId += 0x10000; } subModel = (Model)GameObjectDefinition.modelCache.get(subModelId); if (subModel == null) { subModel = Model.getModel(subModelId & 0xffff); if (subModel == null) { return(null); } if (mirror) { subModel.mirror(); } GameObjectDefinition.modelCache.put(subModel, subModelId); } if (modelCount > 1) { models[m] = subModel; } } if (modelCount > 1) { subModel = new Model(modelCount, models); } } else { int modelType = -1; for (int t = 0; t < definition.modelTypes.Length; t++) { if (definition.modelTypes[t] != type) { continue; } modelType = t; break; } if (modelType == -1) { return(null); } hash = (definition.id << 6) + (modelType << 3) + face + ((long)(animationId + 1) << 32); Model model = (Model)GameObjectDefinition.animatedModelCache.get(hash); if (model != null) { return(model); } int modelId = definition.modelIds[modelType]; bool mirror = definition.rotated ^ (face > 3); if (mirror) { modelId += 0x10000; } subModel = (Model)GameObjectDefinition.modelCache.get(modelId); if (subModel == null) { subModel = Model.getModel(modelId & 0xffff); if (subModel == null) { return(null); } if (mirror) { subModel.mirror(); } GameObjectDefinition.modelCache.put(subModel, modelId); } } bool scale; scale = definition.scaleX != 128 || definition.scaleY != 128 || definition.scaleZ != 128; bool translate; translate = definition.translateX != 0 || definition.translateY != 0 || definition.translateZ != 0; Model animatedModel = new Model(definition.modifiedModelColors == null, Animation.isNullFrame(animationId), face == 0 && animationId == -1 && !scale && !translate, subModel); if (animationId != -1) { animatedModel.createBones(); animatedModel.applyTransformation(animationId); animatedModel.triangleSkin = null; animatedModel.vertexSkin = null; } while (face-- > 0) { animatedModel.rotate90Degrees(); } if (definition.modifiedModelColors != null) { for (int c = 0; c < definition.modifiedModelColors.Length; c++) { animatedModel.recolour(definition.modifiedModelColors[c], definition.originalModelColors[c]); } } if (scale) { animatedModel.scaleT(definition.scaleX, definition.scaleZ, definition.scaleY); } if (translate) { animatedModel.translate(definition.translateX, definition.translateY, definition.translateZ); } animatedModel.applyLighting(64 + definition.ambient, 768 + definition.diffuse * 5, -50, -10, -50, !definition.delayShading); if (definition._solid == 1) { animatedModel.anInt1654 = animatedModel.modelHeight; } GameObjectDefinition.animatedModelCache.put(animatedModel, hash); return(animatedModel); }
public IEnumerator StartupCoroutine() { if (!wasClientStartupCalled) { wasClientStartupCalled = true; } else { throw new InvalidOperationException($"Failed. Cannot call startup on Client multiple times."); } drawLoadingText(20, "Starting up"); if (clientRunning) { rsAlreadyLoaded = true; yield break; } clientRunning = true; bool validHost = true; String s = getDocumentBaseHost(); if (s.EndsWith("jagex.com")) { validHost = true; } if (s.EndsWith("runescape.com")) { validHost = true; } if (s.EndsWith("192.168.1.2")) { validHost = true; } if (s.EndsWith("192.168.1.229")) { validHost = true; } if (s.EndsWith("192.168.1.228")) { validHost = true; } if (s.EndsWith("192.168.1.227")) { validHost = true; } if (s.EndsWith("192.168.1.226")) { validHost = true; } if (s.EndsWith("127.0.0.1")) { validHost = true; } if (!validHost) { genericLoadingError = true; yield break; } if (signlink.cache_dat != null) { for (int i = 0; i < 5; i++) { caches[i] = new FileCache(signlink.cache_dat, signlink.cache_idx[i], i + 1); } } connectServer(); archiveTitle = requestArchive(1, "title screen", "title", expectedCRCs[1], 25); fontSmall = new GameFont("p11_full", archiveTitle, false); fontPlain = new GameFont("p12_full", archiveTitle, false); fontBold = new GameFont("b12_full", archiveTitle, false); GameFont fontFancy = new GameFont("q8_full", archiveTitle, true); drawLogo(); loadTitleScreen(); Archive archiveConfig = requestArchive(2, "config", "config", expectedCRCs[2], 30); Archive archiveInterface = requestArchive(3, "interface", "interface", expectedCRCs[3], 35); Archive archiveMedia = requestArchive(4, "2d graphics", "media", expectedCRCs[4], 40); Archive archiveTextures = requestArchive(6, "textures", "textures", expectedCRCs[6], 45); Archive archiveWord = requestArchive(7, "chat system", "wordenc", expectedCRCs[7], 50); Archive archiveSounds = requestArchive(8, "sound effects", "sounds", expectedCRCs[8], 55); tileFlags = new byte[4, 104, 104]; intGroundArray = CollectionUtilities.Create3DJaggedArray <int>(4, 105, 105); worldController = new WorldController(intGroundArray); for (int z = 0; z < 4; z++) { currentCollisionMap[z] = new CollisionMap(); } minimapImage = new Sprite(512, 512); Archive archiveVersions = requestArchive(5, "update list", "versionlist", expectedCRCs[5], 60); drawLoadingText(60, "Connecting to update server"); StartOnDemandFetcher(archiveVersions); Animation.init(onDemandFetcher.getAnimCount()); Model.init(onDemandFetcher.fileCount(0), onDemandFetcher); songChanging = true; onDemandFetcher.request(2, nextSong); while (onDemandFetcher.immediateRequestCount() > 0) { processOnDemandQueue(); yield return(new WaitForSeconds(0.1f)); if (onDemandFetcher.failedRequests > 3) { loadError(); yield break; } } drawLoadingText(65, "Requesting animations"); int fileRequestCount = onDemandFetcher.fileCount(1); for (int id = 0; id < fileRequestCount; id++) { onDemandFetcher.request(1, id); } while (onDemandFetcher.immediateRequestCount() > 0) { int remaining = fileRequestCount - onDemandFetcher.immediateRequestCount(); if (remaining > 0) { drawLoadingText(65, "Loading animations - " + (remaining * 100) / fileRequestCount + "%"); } try { processOnDemandQueue(); } catch (Exception e) { Console.WriteLine($"Failed to process animation demand queue. Reason: {e.Message} \n Stack: {e.StackTrace}"); signlink.reporterror($"Failed to process animation demand queue. Reason: {e.Message} \n Stack: {e.StackTrace}"); throw; } yield return(new WaitForSeconds(0.1f)); if (onDemandFetcher.failedRequests > 3) { loadError(); yield break; } } drawLoadingText(70, "Requesting models"); fileRequestCount = onDemandFetcher.fileCount(0); for (int id = 0; id < fileRequestCount; id++) { int modelId = onDemandFetcher.getModelId(id); if ((modelId & 1) != 0) { onDemandFetcher.request(0, id); } } fileRequestCount = onDemandFetcher.immediateRequestCount(); while (onDemandFetcher.immediateRequestCount() > 0) { int remaining = fileRequestCount - onDemandFetcher.immediateRequestCount(); if (remaining > 0) { drawLoadingText(70, "Loading models - " + (remaining * 100) / fileRequestCount + "%"); } processOnDemandQueue(); yield return(new WaitForSeconds(0.1f)); } GC.Collect(); if (caches[0] != null) { drawLoadingText(75, "Requesting maps"); onDemandFetcher.request(3, onDemandFetcher.getMapId(0, 47, 48)); yield return(null); onDemandFetcher.request(3, onDemandFetcher.getMapId(1, 47, 48)); yield return(null); onDemandFetcher.request(3, onDemandFetcher.getMapId(0, 48, 48)); yield return(null); onDemandFetcher.request(3, onDemandFetcher.getMapId(1, 48, 48)); yield return(null); onDemandFetcher.request(3, onDemandFetcher.getMapId(0, 49, 48)); yield return(null); onDemandFetcher.request(3, onDemandFetcher.getMapId(1, 49, 48)); yield return(null); onDemandFetcher.request(3, onDemandFetcher.getMapId(0, 47, 47)); yield return(null); onDemandFetcher.request(3, onDemandFetcher.getMapId(1, 47, 47)); yield return(null); onDemandFetcher.request(3, onDemandFetcher.getMapId(0, 48, 47)); yield return(null); onDemandFetcher.request(3, onDemandFetcher.getMapId(1, 48, 47)); yield return(null); onDemandFetcher.request(3, onDemandFetcher.getMapId(0, 48, 148)); yield return(null); onDemandFetcher.request(3, onDemandFetcher.getMapId(1, 48, 148)); yield return(null); fileRequestCount = onDemandFetcher.immediateRequestCount(); while (onDemandFetcher.immediateRequestCount() > 0) { int remaining = fileRequestCount - onDemandFetcher.immediateRequestCount(); if (remaining > 0) { drawLoadingText(75, "Loading maps - " + (remaining * 100) / fileRequestCount + "%"); } processOnDemandQueue(); yield return(new WaitForSeconds(0.1f)); } } fileRequestCount = onDemandFetcher.fileCount(0); for (int id = 0; id < fileRequestCount; id++) { int modelId = onDemandFetcher.getModelId(id); byte priority = 0; if ((modelId & 8) != 0) { priority = 10; } else if ((modelId & 0x20) != 0) { priority = 9; } else if ((modelId & 0x10) != 0) { priority = 8; } else if ((modelId & 0x40) != 0) { priority = 7; } else if ((modelId & 0x80) != 0) { priority = 6; } else if ((modelId & 2) != 0) { priority = 5; } else if ((modelId & 4) != 0) { priority = 4; } if ((modelId & 1) != 0) { priority = 3; } if (priority != 0) { onDemandFetcher.setPriority(priority, 0, id); } } onDemandFetcher.preloadRegions(membersWorld); //Remove low memory check. int count = onDemandFetcher.fileCount(2); for (int id = 1; id < count; id++) { if (onDemandFetcher.midiIdEqualsOne(id)) { onDemandFetcher.setPriority((byte)1, 2, id); } } drawLoadingText(80, "Unpacking media"); //Default cache can cause some errors, so wecan surpress them here. try { InitializeUnpackedMedia(archiveMedia); } catch (Exception e) { Console.WriteLine($"Media Error: {e}"); } drawLoadingText(83, "Unpacking textures"); Rasterizer.unpackTextures(archiveTextures); Rasterizer.calculatePalette(0.80000000000000004D); Rasterizer.resetTextures(); drawLoadingText(86, "Unpacking config"); AnimationSequence.unpackConfig(archiveConfig); GameObjectDefinition.load(archiveConfig); FloorDefinition.load(archiveConfig); ItemDefinition.load(archiveConfig); EntityDefinition.load(archiveConfig); IdentityKit.load(archiveConfig); SpotAnimation.load(archiveConfig); Varp.load(archiveConfig); VarBit.load(archiveConfig); ItemDefinition.membersWorld = membersWorld; //Removed low memory check drawLoadingText(90, "Unpacking sounds"); byte[] soundData = archiveSounds.decompressFile("sounds.dat"); Default317Buffer stream = new Default317Buffer(soundData); Effect.load(stream); drawLoadingText(95, "Unpacking interfaces"); GameFont[] fonts = { fontSmall, fontPlain, fontBold, fontFancy }; RSInterface.unpack(archiveInterface, fonts, archiveMedia); drawLoadingText(100, "Preparing game engine"); for (int _y = 0; _y < 33; _y++) { int firstXOfLine = 999; int lastXOfLine = 0; for (int _x = 0; _x < 34; _x++) { if (minimapBackgroundImage.pixels[_x + _y * minimapBackgroundImage.width] == 0) { if (firstXOfLine == 999) { firstXOfLine = _x; } continue; } if (firstXOfLine == 999) { continue; } lastXOfLine = _x; break; } compassHingeSize[_y] = firstXOfLine; compassWidthMap[_y] = lastXOfLine - firstXOfLine; } for (int _y = 5; _y < 156; _y++) { int min = 999; int max = 0; for (int _x = 25; _x < 172; _x++) { if (minimapBackgroundImage.pixels[_x + _y * minimapBackgroundImage.width] == 0 && (_x > 34 || _y > 34)) { if (min == 999) { min = _x; } continue; } if (min == 999) { continue; } max = _x; break; } minimapLeft[_y - 5] = min - 25; minimapLineWidth[_y - 5] = max - min; } Rasterizer.setBounds(479, 96); chatboxLineOffsets = Rasterizer.lineOffsets; Rasterizer.setBounds(190, 261); sidebarOffsets = Rasterizer.lineOffsets; Rasterizer.setBounds(512, 334); viewportOffsets = Rasterizer.lineOffsets; int[] ai = new int[9]; for (int i8 = 0; i8 < 9; i8++) { int k8 = 128 + i8 * 32 + 15; int l8 = 600 + k8 * 3; int i9 = Rasterizer.SINE[k8]; ai[i8] = l8 * i9 >> 16; } WorldController.setupViewport(500, 800, 512, 334, ai); GameObject.clientInstance = this; GameObjectDefinition.clientInstance = this; EntityDefinition.clientInstance = this; //TODO: Disabled censor //Censor.load(archiveWord); mouseDetection = new MouseDetection(this); //startRunnable(mouseDetection, 10); yield break; }