Skip to content

Commit 3b16eb1

Browse files
authored
Merge pull request #303 from runejs/feature/construction
Construction game engine mods part 1
2 parents 08e29bf + 1b63ce2 commit 3b16eb1

24 files changed

+736
-144
lines changed

data/config/xteas/468.json

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
[
2+
{
3+
"archive": 5,
4+
"group": 33,
5+
"name_hash": -1155051794,
6+
"name": "l29_79",
7+
"mapsquare": 7503,
8+
"key": [
9+
-205505693,
10+
-1069477933,
11+
-1042446848,
12+
-93348110
13+
]
14+
},
15+
{
16+
"archive": 5,
17+
"group": 35,
18+
"name_hash": -1154396392,
19+
"name": "l30_79",
20+
"mapsquare": 7759,
21+
"key": [
22+
-1255219039,
23+
-277284099,
24+
1886972034,
25+
-723091074
26+
]
27+
}
28+
]

src/game-engine/config/index.ts

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,15 @@ import { Quest } from '@engine/world/actor/player/quest';
1919
import { ItemSpawn, loadItemSpawnConfigurations } from '@engine/config/item-spawn-config';
2020
import { loadSkillGuideConfigurations, SkillGuide } from '@engine/config/skill-guide-config';
2121
import { loadMusicRegionConfigurations, MusicTrack } from '@engine/config/music-regions-config';
22-
import { loadXteaRegionFiles, XteaRegion } from '@runejs/filestore';
22+
import { LandscapeObject, loadXteaRegionFiles, ObjectConfig, XteaRegion } from '@runejs/filestore';
2323

2424
require('json5/lib/register');
2525

2626

2727

2828
export let itemMap: { [key: string]: ItemDetails };
2929
export let itemIdMap: { [key: number]: string };
30+
export let objectMap: { [key: number]: ObjectConfig };
3031
export let itemPresetMap: ItemPresetConfiguration;
3132
export let npcMap: { [key: string]: NpcDetails };
3233
export let npcIdMap: { [key: number]: string };
@@ -65,6 +66,9 @@ export async function loadGameConfigurations(): Promise<void> {
6566

6667
shopMap = await loadShopConfigurations('data/config/shops/');
6768
skillGuides = await loadSkillGuideConfigurations('data/config/skill-guides/');
69+
70+
objectMap = {};
71+
6872
logger.info(`Loaded ${musicRegions.length} music regions, ${Object.keys(itemMap).length} items, ${itemSpawns.length} item spawns, ` +
6973
`${Object.keys(npcMap).length} npcs, ${npcSpawns.length} npc spawns, ${Object.keys(shopMap).length} shops and ${skillGuides.length} skill guides.`);
7074
}
@@ -170,6 +174,21 @@ export const findNpc = (npcKey: number | string): NpcDetails | null => {
170174
};
171175

172176

177+
export const findObject = (objectId: number): ObjectConfig | null => {
178+
if(!objectMap[objectId]) {
179+
const object = filestore.objectStore.getObject(objectId);
180+
if(!object) {
181+
return null;
182+
}
183+
184+
objectMap[objectId] = object;
185+
return object;
186+
} else {
187+
return objectMap[objectId];
188+
}
189+
};
190+
191+
173192
export const findShop = (shopKey: string): Shop | null => {
174193
if(!shopKey) {
175194
return null;

src/game-engine/net/inbound-packets.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,14 +39,19 @@ export async function loadPackets(): Promise<Map<number, InboundPacket>> {
3939
export function handlePacket(player: Player, packetId: number, packetSize: number, buffer: ByteBuffer): boolean {
4040
const incomingPacket = incomingPackets.get(packetId);
4141

42-
if (!incomingPacket) {
42+
if(!incomingPacket) {
4343
logger.info(`Unknown packet ${packetId} with size ${packetSize} received.`);
4444
return false;
4545
}
4646

4747
new Promise<void>(resolve => {
48-
incomingPacket.handler(player, { packetId, packetSize, buffer });
48+
try {
49+
incomingPacket.handler(player, { packetId, packetSize, buffer });
50+
} catch(error) {
51+
logger.error(`Error handling inbound packet ${packetId} with size ${packetSize}`);
52+
logger.error(error);
53+
}
4954
resolve();
50-
}).catch(error => logger.error(`Error handling inbound packet ${packetId} with size ${packetSize}: ${error}`));
55+
});
5156
return true;
5257
}

src/game-engine/net/inbound-packets/object-interaction-packet.js

Lines changed: 0 additions & 98 deletions
This file was deleted.
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
import { logger } from '@runejs/core';
2+
3+
import { filestore, world } from '@engine/game-server';
4+
import { Position } from '@engine/world/position';
5+
import { getVarbitMorphIndex } from '@engine/util/varbits';
6+
import { PacketData } from '@engine/net/inbound-packets';
7+
import { Player, Rights } from '@engine/world/actor/player/player';
8+
9+
10+
interface ObjectInteractionData {
11+
objectId: number;
12+
x: number;
13+
y: number;
14+
}
15+
16+
type objectInteractionPacket = (packet: PacketData) => ObjectInteractionData;
17+
18+
19+
const option1: objectInteractionPacket = packet => {
20+
const { buffer } = packet;
21+
const objectId = buffer.get('short', 'u');
22+
const y = buffer.get('short', 'u');
23+
const x = buffer.get('short', 'u', 'le');
24+
return { objectId, x, y };
25+
};
26+
27+
const option2: objectInteractionPacket = packet => {
28+
const { buffer } = packet;
29+
const x = buffer.get('short', 'u', 'le');
30+
const y = buffer.get('short', 'u', 'le');
31+
const objectId = buffer.get('short', 'u', 'le');
32+
return { objectId, x, y };
33+
};
34+
35+
const option3: objectInteractionPacket = packet => {
36+
const { buffer } = packet;
37+
const y = buffer.get('short', 'u');
38+
const objectId = buffer.get('short', 'u');
39+
const x = buffer.get('short', 'u');
40+
return { objectId, x, y };
41+
};
42+
43+
const option4: objectInteractionPacket = packet => {
44+
const { buffer } = packet;
45+
const x = buffer.get('short', 'u', 'le');
46+
const objectId = buffer.get('short', 'u', 'le');
47+
const y = buffer.get('short', 'u', 'le');
48+
return { objectId, x, y };
49+
};
50+
51+
const option5: objectInteractionPacket = packet => {
52+
const { buffer } = packet;
53+
const objectId = buffer.get('short', 'u');
54+
const y = buffer.get('short', 'u', 'le');
55+
const x = buffer.get('short', 'u', 'le');
56+
return { objectId, x, y };
57+
};
58+
59+
60+
const objectInteractionPackets: { [key: number]: { packetDef: objectInteractionPacket, index: number } } = {
61+
30: { packetDef: option1, index: 0 },
62+
164: { packetDef: option2, index: 1 },
63+
183: { packetDef: option3, index: 2 },
64+
229: { packetDef: option4, index: 3 },
65+
62: { packetDef: option5, index: 4 },
66+
};
67+
68+
69+
const objectInteractionPacket = (player: Player, packet: PacketData) => {
70+
const { packetId } = packet;
71+
72+
const { objectId, x, y } = objectInteractionPackets[packetId].packetDef(packet);
73+
const level = player.position.level;
74+
const objectPosition = new Position(x, y, level);
75+
const { object: landscapeObject, cacheOriginal } = world.findObjectAtLocation(player, objectId, objectPosition);
76+
if(!landscapeObject) {
77+
if(player.rights === Rights.ADMIN) {
78+
player.sendMessage(`Custom object ${objectId} @[${objectPosition.key}]`);
79+
}
80+
return;
81+
}
82+
83+
let objectConfig = filestore.configStore.objectStore.getObject(objectId);
84+
if (objectConfig.configChangeDest) {
85+
let morphIndex = -1;
86+
if(objectConfig.varbitId === -1) {
87+
if(objectConfig.configId !== -1) {
88+
morphIndex = player.metadata['configs'] && player.metadata['configs'][objectConfig.configId] ?
89+
player.metadata['configs'][objectConfig.configId] : 0;
90+
}
91+
} else {
92+
morphIndex = getVarbitMorphIndex(objectConfig.varbitId, player.metadata['configs']);
93+
}
94+
if(morphIndex !== -1) {
95+
objectConfig = filestore.configStore.objectStore.getObject(objectConfig.configChangeDest[morphIndex]);
96+
}
97+
}
98+
99+
const actionIdx = objectInteractionPackets[packetId].index;
100+
let optionName = `action-${actionIdx + 1}`;
101+
if(objectConfig.options && objectConfig.options.length >= actionIdx) {
102+
if(!objectConfig.options[actionIdx]) {
103+
// Invalid action
104+
logger.error(`1: Invalid object ${objectId} option ${actionIdx + 1}, options: ${JSON.stringify(objectConfig.options)}`);
105+
return;
106+
}
107+
108+
optionName = objectConfig.options[actionIdx];
109+
} else {
110+
// Invalid action
111+
logger.error(`2: Invalid object ${objectId} option ${actionIdx + 1}, options: ${JSON.stringify(objectConfig.options)}`);
112+
return;
113+
}
114+
115+
player.actionPipeline.call('object_interaction', player, landscapeObject, objectConfig, objectPosition, optionName.toLowerCase(), cacheOriginal);
116+
};
117+
118+
119+
export default Object.keys(objectInteractionPackets).map(opcode => ({
120+
opcode: parseInt(opcode, 10),
121+
size: 6,
122+
handler: objectInteractionPacket
123+
}));

0 commit comments

Comments
 (0)