Below is a basic instance implementation for anyone who might be interested. It's not very complex, but beginners may find it interesting. Please note it does not support gmap or multi-level instances, though this would be a relatively simple modification. Maybe a good challenge for someone looking to learn?
To implement this, replace some of the constants with default paths/levels.
Control-Instance (NPC)
PHP Code:
/**
Instance control npc. Manages instances, and handles creation/destruction.
*/
//Set instance level path, default exit level (along with x, y coords)
function onCreated() {
this.path = "Instance Path";
this.defaultExit = "Default Exit Level";
this.exitX = 30;
this.exitY = 1;
destroyInstances();
}
/**
Params:
levelName: String
levelPath: String
data: Any
className: String
Ret:
id: String
Creates new instance level and instance object. Stores object in memory
indexed by levelname (id). New instance is constructed with standard
instance class and user-defined instance class if provided.
*/
public function createInstance(levelName, levelPath, data, className) {
if (levelName == NULL) return;
temp.id = levelName.substring(0, levelName.length() - 3) @ int(timevar2) @ ".nw";
if (this.(@ id) != NULL) {
sleep(1);
temp.id = createInstance(levelName, levelPath, data, className);
return id;
}
copyFile(levelPath @ levelName, this.path @ id);
this.(@ id) = new TStaticVar();
this.(@ id).join("Instance");
this.(@ id).init(id, data);
temp.npc = findLevel(id).putnpc2(30, 30, "");
temp.npc.join("Instance_Level");
if (className != NULL) {
temp.cnpc = findLevel(id).putnpc2(30, 30, "");
temp.cnpc.join("" @ className @ "");
}
return id;
}
/**
Params:
id: String
*/
public function destroyInstance(id) {
if (fileexists(this.path @ id)) {
if (this.(@ id).playerCount > 0) this.(@ id).removePlayers(this.defaultExit, this.exitX, this.exitY);
clearNPCs(id);
deletefile(this.path @ id);
if (this.(@ id) != NULL) this.(@ id).destroy();
}
}
function clearNPCs(levelName) {
temp.level = findLevel(levelName);
for (temp.npc : level.npcs) {
npc.destroy();
}
}
/**
Params:
id: String
Ret:
instance: Object
*/
public function getInstanceByID(id) {
return this.(@ id);
}
//Destroy all instances when restarting server
function destroyInstances() {
temp.folder.loadfolder(this.path @ "*.nw", false);
for (temp.f : temp.folder) {
destroyInstance(temp.f);
}
}
function copyFile(src, dest) {
temp.contents.loadstring(src);
temp.contents.savestring(dest, 0);
}
Instance_Creator (Class)
PHP Code:
function init(levelName, levelPath, data, className) {
temp.npc = findNPC("Control-Instance");
this.id = npc.createInstance(levelName, levelPath, data, className);
}
function warpPlayer(pl, x, y) {
findplayer(pl).setlevel2(this.id, x, y);
}
function warpPlayers(pls, x, y) {
for (temp.pl : pls) {
findplayer(temp.pl).setlevel2(this.id, x, y);
}
}
function warpPlayerRandom(pl, x, y, dx, dy) {
findplayer(pl).setlevel2(this.id, x + random(-dx, dx), y + random(-dy, dy));
}
function warpPlayersRandom(pls, x, y, dx, dy) {
for (temp.pl : pls) {
findplayer(temp.pl).setlevel2(this.id, x + random(-dx, dx), y + random(-dy, dy));
}
}
Instance_Level (Class)
PHP Code:
// Get instance object
function onCreated() {
temp.npc = findNPC("Control-Instance");
this.instance = npc.getInstanceByID(this.level.name);
this.initiated = false;
init();
}
function init() {
if (findlevel(this.instance.getLevelName()).players.size() == 0) {
sleep(5);
init();
} else {
scheduleevent(30, "UpdateInstance", NULL);
}
}
//Check if players remain in instance, destroy if not
function onUpdateInstance() {
if (findlevel(this.instance.getLevelName()).players.size() == 0) {
temp.npc = findNPC("Control-Instance");
npc.destroyInstance(this.level.name);
}
scheduleevent(30, "UpdateInstance", NULL);
}
Instance (Class)
PHP Code:
/**
Params:
levelName: String
data: any
*/
public function init(levelName, data) {
this.data = data;
this.levelName = levelName;
}
// Returns current player count on level
public function getPlayerCount() {
return arraylen(findLevel(this.levelName).players);
}
// Returns level name
public function getLevelName() {
return this.levelName;
}
// Returns instance data
public function getData() {
return this.data;
}
// Sets instance data
public function setData(d) {
this.data = d;
}
// Removes all players from level
public function removePlayers(dest, x, y) {
temp.lvl = findLevel(this.levelName);
for (temp.pl : temp.lvl.players) {
temp.pl.setlevel2(dest, x, y);
}
}
Now this code really isn't great, there are several design inconsistencies, etc. It's also not useful for servers atm as I'd imagine most wouldn't want to just have single level instances. I'll update this soon with a better implementation! May still be of use to someone looking to build an instance system.