Author Topic: Scriptgroup, Scriptobject  (Read 1591 times)

how does that onplant thing even work? it won't load bricks not in a chunk, and won't put them in one?

I'll be very generous here and provide the chunk system from my Minecraft game-mode.

Code: (chunk.cs) [Select]
function roundToChunkIndex( %pos )
{
%x = mFloor( getWord( %pos, 0 ) / 16 ); // 32x Cube
%y = mFloor( getWord( %pos, 1 ) / 16 ); // 32x Cube

return %x SPC %y;
}

function chunkGroup()
{
if ( !strLen( $MC::CurrWorld ) )
{
return -1;
}

if ( isObject( %obj = nameToID( "chunkGroup" ) ) )
{
return %obj;
}

%obj = new scriptGroup( "chunkGroup" );
%obj.loadWorld();
%obj.saveWorldTick = %obj.schedule( 0, "saveWorldTick" );

return %obj;
}

function chunkGroup::loadWorld( %this )
{
if ( !strLen( $MC::CurrWorld ) )
{
return false;
}

%path = "config/mc/world/" @ $MC::CurrWorld @ "/world.dat";

if ( !isFile( %path ) )
{
return false;
}

%fo = new fileObject();
%fo.openForWrite( %path );

while ( !%fo.isEOF() )
{
%line = %fo.readLine();

if ( !strLen( %line ) )
{
continue;
}

if ( getSubStr( %line, 0, 1 ) $= "#" )
{
continue;
}

%ploc = strPos( %line, "\t" );

if ( %ploc < 0 )
{
continue;
}

%field = getSubStr( %line, 0, %ploc );
%value = getSubStr( %line, %ploc + 1, strLen( %line ) );

switch$ ( %field )
{
case "name": // currently unused
case "seed": $MC::CurrSeed = %value;
case "time": mcTickSO().time = %value % 24000;
}
}

%fo.close();
%fo.delete();

return true;
}

function chunkGroup::saveWorldTick( %this )
{
cancel( %this.saveWorldTick );

if ( !strLen( $MC::CurrWorld ) )
{
return false;
}

%path = "config/mc/world/" @ $MC::CurrWorld @ "/world.dat";

if ( !isWriteableFileName( %path ) )
{
return false;
}

%fo = new fileObject();
%fo.openForWrite( %path );

%fo.writeLine( "name" TAB $MC::CurrWorld );
%fo.writeLine( "seed" TAB $MC::CurrSeed );
%fo.writeLine( "time" TAB mcTickSO().time % 24000 );

%fo.close();
%fo.delete();

%this.saveWorldTick = %this.schedule( 120000, "saveWorldTick" );
return true;
}

function chunkSO( %x, %y, %dim )
{
if ( !strLen( $MC::CurrWorld ) )
{
return -1;
}

if ( !strLen( %dim ) )
{
%dim = 0;
}

%ndst = ( %dim != 0 ? "DIM_" @ %dim @ "_" : "" );

%name = "chunkSO_" @ %ndst @ %x @ "_" @ %y;

if ( isObject( %obj = nameToID( %name ) ) )
{
return %obj;
}

%obj = new scriptObject()
{
class = "chunkSO";

dimension = %dim;
position = %x SPC %y SPC 0;

initializing = true;
index = %x SPC %y;
blockCount = 0;
};

%obj.setName( %name );
chunkGroup().add( %obj );

if ( !%obj.loadChunk() )
{
%obj.generateChunk();
}
else
{
%obj.unloadCheckTick();
}

return %obj;
}

function chunkSO::unloadCheckTick( %this )
{
cancel( %this.unloadCheckTick );

if ( vectorDist( %this.position, "0 0 0" ) <= 1 )
{
return;
}

%near = false;
%count = clientGroup.getCount();

for ( %i = 0 ; %i < %count ; %i++ )
{
%cl = clientGroup.getObject( %i );

if ( !isObject( %pl = %cl.player ) )
{
continue;
}

if ( %pl.dimension !$= %this.dimension )
{
continue;
}

if ( vectorDist( %this.position, roundToChunkIndex( %pl.getPosition() ) SPC 0 ) <= 3 )
{
%near = true;
break;
}
}

if ( !%near )
{
%this.unloadChunk();
return;
}

%this.unloadCheckTick = %this.schedule( 5000, "unloadCheckTick" );
}

function chunkSO::unloadChunk( %this )
{
if ( %this.unloading )
{
return;
}

cancel( %this.loadChunkTick );
cancel( %this.generateChunkTick );

%this.unloading = true;
%this.unloadChunkTick = %this.schedule( 100, "unloadChunkTick", 0 );
}

function chunkSO::unloadChunkTick( %this, %idx )
{
cancel( %this.unloadChunkTick );

%quotaUsage = 0;
%quotaLimit = 32;

for ( %idx ; %idx < %this.blockCount && %quotaUsage < %quotaLimit ; %idx++ )
{
if ( !isObject( %obj = %this.blockObject[ %idx ] ) )
{
continue;
}

%obj.delete();
%quotaUsage++;
}

if ( %idx >= %this.blockCount )
{
%this.schedule( 0, "delete" );
return;
}

%this.unloadChunkTick = %this.schedule( 100, "unloadChunkTick", %idx );
}

function chunkSO::getFilePath( %this )
{
if ( !strLen( $MC::CurrWorld ) )
{
return "";
}

%index = strReplace( %this.index, " ", "_" );

if ( %this.dimension != 0 )
{
%dim_string = "/DIM_" @ %this.dimension;
}

return "config/mc/world/" @ $MC::CurrWorld @ %dim_string @ "/chunk_" @ %index @ ".chk";
}

function chunkSO::getPosition( %this )
{
return vectorAdd( vectorScale( %this.position, 16 ), "0 0" SPC 1024 * %this.dimension );
}

function chunkSO::setBlock( %this, %x, %y, %z, %type )
{
%x = mFloor( %x );
%y = mFloor( %y );
%z = mfloor( %z );

if ( %x < 0 )
{
return false;
}

if ( %y < 0 )
{
return false;
}

if ( %z < 0 )
{
return false;
}

if ( %x > 15 )
{
return false;
}

if ( %y > 15 )
{
return false;
}

if ( %z > 255 )
{
return false;
}

%curr = %this.blockByPos[ %x SPC %y SPC %z ];

if ( strLen( %curr ) && %curr >= 0 )
{
if ( isObject( %obj = %this.blockObject[ %curr ] ) )
{
%obj.delete();
}

%idx = %curr;
}
else
{
%idx = %this.blockCount;
%this.blockCount++;
}

%this.blockType[ %idx ] = "";
%this.blockPos[ %idx ] = "";
%this.blockByPos[ %x SPC %y SPC %z ] = "";
%this.blockObject[ %idx ] = "";

if ( !isObject( %db = "mc_blockData_" @ %type ) )
{
%this.reflowBlockArray( %idx );
return true;
}

%this.generatedPoint[ %x, %y, %z ] = true;
%this.blockType[ %idx ] = %type;
%this.blockPos[ %idx ] = %x SPC %y SPC %z;
%this.blockByPos[ %x SPC %y SPC %z ] = %idx;

%rpos = vectorAdd( %this.getPosition(), %x SPC %y SPC %z );
%rpos = vectorAdd( %rpos, "0 0" SPC $MC::GlobalBlockOffsetZ );

if ( strLen( %db.mcBlockOffsetZ ) )
{
%rpos = vectorAdd( %rpos, "0 0" SPC %db.mcBlockOffsetZ );
}

%obj = new fxDTSBrick()
{
position = %rpos;
dataBlock = %db;
colorId = 0;
// printId = $printNameTable[ "2x2f/" @ ( strLen( %db.printUI ) ? %db.printUI : "MCNone" ) ];
// colorFxId = %db.colorFxId;
// shapeFxId = %db.shapeFxId;
isPlanted = true;

chunkSO = %this;
indexInChunk = %idx;
};

%obj.setTrusted( true );
getMCBrickGroup().add( %obj );
%obj.plant();

%this.blockObject[ %idx ] = %obj;

if ( isFunction( %func = "block_" @ %type @ "_onPlant" ) )
{
call( %func, %obj, %this );
}

if ( !%this.initializing )
{
%this.saveChunk();
}

return true;
}

function chunkSO::getBlock( %this, %x, %y, %z )
{
return %this.blockType[ %this.blockByPos[ %x SPC %y SPC %z ] ];
}

function chunkSO::reflowBlockArray( %this, %index )
{
if ( !strLen( %index ) || %index < 0 || %index >= %this.blockCount )
{
return false;
}

for ( %i = %index ; %i < %this.blockCount ; %i++ )
{
%this.blockType[ %i ] = %this.blockType[ %i + 1 ];
%this.blockPos[ %i ] = %this.blockPos[ %i + 1 ];

%px = getWord( %this.blockPos[ %i ], 0 );
%py = getWord( %this.blockPos[ %i ], 1 );
%pz = getWord( %this.blockPos[ %i ], 2 );

%this.blockByPos[ %px SPC %py SPC %pz ] = %i;
%this.blockObject[ %i ] = %this.blockObject[ %i + 1 ];

if ( isObject( %obj = %this.blockObject[ %i ] ) )
{
%obj.indexInChunk = %i;
}
}

%this.blockCount--;
%this.blockType[ %this.blockCount ] = "";
%this.blockObject[ %this.blockCount ] = "";
%this.blockPos[ %this.blockCount ] = "";

return true;
}

Code: (chunk_saving.cs) [Select]
$chunkd::XYBase = "0123456789abcdef";

function chunkSO::loadChunkTick( %this, %str, %idx )
{
cancel( %this.loadChunkTick );

%quotaUsage = 0;
%quotaLimit = 32;
%count = getFieldCount( %str );

for ( %idx ; %idx < %count && %quotaUsage < %quotaLimit ; %idx++ )
{
%field = getField( %str, %idx );

%px = strPos( $chunkd::XYBase, getSubStr( %field, 0, 1 ) );
%py = strPos( $chunkd::XYBase, getSubStr( %field, 1, 1 ) );
%pz = mFloor( getSubStr( %field, 2, 3 ) );
%tp = getSubStr( %field, 5, strLen( %field ) );

%this.setBlock( %px, %py, %pz, %tp );
%quotaUsage++;
}

if ( %idx >= %count )
{
%this.initializing = false;
return;
}

%this.loadChunkTick = %this.schedule( 128, "loadChunkTick", %str, %idx );
}

function chunkSO::loadChunk( %this )
{
if ( %this.blockCount )
{
return true;
}

if ( isEventPending( %this.loadChunkTick ) )
{
return true;
}

if ( isEventPending( %this.generateChunkTick ) )
{
return true;
}

if ( !isFile( %path = %this.getFilePath() ) )
{
return false;
}

%fo = new fileObject();
%fo.openForRead( %path );

%str = %fo.readLine();

while( !%fo.isEOF() )
{
%str = %str NL %fo.readLine();
}

%fo.close();
%fo.delete();

%str = strReplace( %str, "\xFA", "\t" );
%this.loadChunkTick( %str, 0 );
}

function chunkSO::saveChunk( %this )
{
if ( %this.unloading )
{
return;
}

if ( getSimTime() - %this.lastSaveTime < 30000 )
{
if ( isEventPending( %this.queuedSavePoint ) )
{
%this.queuedSavePoint = %this.schedule( ( getSimTime() - %this.lastSaveTime ) + 16, "saveChunk" );
}

return false;
}
else if ( isEventPending( %this.queuedSavePoint ) )
{
cancel( %this.queuedSavePoint );
}

if ( isEventPending( %this.loadChunkTick ) )
{
return false;
}

if ( isEventPending( %this.generateChunkTick ) )
{
return false;
}

%path = %this.getFilePath();
%this.lastSaveTime = getSimTime();

if ( !isWriteableFileName( %path ) )
{
return false;
}

%fo = new fileObject();
%fo.openForWrite( %path );

for ( %i = 0 ; %i < %this.blockCount ; %i++ )
{
%type = %this.blockType[ %i ];
%pos = %this.blockPos[ %i ];
%px = getWord( %pos, 0 );
%py = getWord( %pos, 1 );
%pz = getWord( %pos, 2 );
%px = getSubStr( $chunkd::XYBase, %px, 1 );
%py = getSubStr( $chunkd::XYBase, %py, 1 );

if ( strLen( %pz ) == 2 )
{
%pz = "0" @ %pz;
}
else if ( strLen( %pz ) == 1 )
{
%pz = "00" @ %pz;
}

%string = %string @ ( strLen( %string ) ? "\xFA" : "" ) @ %px @ %py @ %pz @ %type;
}

%fo.writeLine( %string );
%fo.close();
%fo.delete();

return true;
}

Code: (chunk_properties.cs) [Select]
// Overworld
function chunkSO::getTerrainHeight( %this, %x, %y )
{
if ( strLen( %height = %this.terrainHeight[ %x, %y ] ) )
{
return %height;
}

%height = 63;

if ( %height > 119 )
{
%height = 119;
}

%this.terrainHeight[ %x, %y ] = %height;
return %height;
}

// These functions are currently just dummy functions.
function chunkSO::getBiome( %this, %x, %y )
{
return "forest";
}

function chunkSO::getTemperature( %this, %x, %y )
{
return 50;
}

function chunkSO::getHumidity( %this, %x, %y )
{
return 50;
}

// Nether
// Aether
// The End

Code: (chunk_generate.cs) [Select]
function chunkSO::generateChunk( %this )
{
if ( %this.blockCount )
{
return;
}

switch$ ( %this.dimension )
{
case 2: %this.generateTheEnd();
case 1: %this.generateAether();
case 0: %this.generateOverworld();
case -1: %this.generateNether();
}

%this.initializing = false;
%this.saveChunk();
%this.unloadCheckTick();
}

// Overworld
function chunkSO::generateOverworld( %this )
{
// Generate base terrain.
for ( %x = 0 ; %x < 16 ; %x++ )
{
for ( %y = 0 ; %y < 16 ; %y++ )
{
%height = %this.getTerrainHeight( %x, %y );

%this.setBlock( %x, %y, %height, "grass" );
}
}

// Generate trees.
%tree_count = getRandom( -5, 3 );

for ( %i = 0 ; %i < %tree_count ; %i++ )
{
%x = getRandom( 4, 12 );
%y = getRandom( 4, 12 );

%x = mFloor( %x / 2 ) * 2;
%y = mFloor( %y / 2 ) * 2;

if ( %water[ %x, %y ] )
{
continue;
}

if ( %madeTree[ %x, %y ] )
{
continue;
}

%madeTree[ %x, %y ] = true;

%this.generateTree( %x, %y );
}
}

function chunkSO::generateTree( %this, %x, %y )
{
%terr = %this.getTerrainHeight( %x, %y );

%height = getRandom( 4, 10 );
%width = getRandom( 3, 5 );

if ( %width >= %height )
{
%width = %height - 1;
}

for ( %z = 1 ; %z <= %height ; %z++ )
{
%this.setBlock( %x, %y, %terr + %z, "log" );
}

%trp = %x SPC %y SPC %terr + %height;

for ( %xi = %x - %width ; %xi <= %x + %width ; %xi++ )
{
for ( %yi = %y - %width ; %yi <= %y + %width ; %yi++ )
{
for ( %zi = %terr + 1 ; %zi <= %terr + %height + %width ; %zi++ )
{
if ( %xi == %x && %yi == %y && %zi <= %terr + %height )
{
continue;
}

if ( vectorDist( %xi SPC %yi SPC %zi, %trp ) > %width )
{
continue;
}

%this.setBlock( %xi, %yi, %zi, "leaves" );
}
}
}
}

function chunkSO::generateBelowTerrain( %px, %py, %pz, %bl, %th, %obj )
{
if ( $MC::Clearing )
{
return;
}

// px: generate 1 block out from this starting point
// py: generate 1 block out from this starting point
// pz: generate 1 block out from this starting point
// bl: the starting point is this amount of blocks below ground level
// th: ground level at starting point
// obj: an object at starting point

//if ( getRandom() <= 0.02 ) // Create a cave system?
//{
// chunkSO::generateBelowCaveSystem( %px, %py, %pz ); // Generate the cave system.
// return; // Don't do normal underground generation.
//}

for ( %x = -1 ; %x <= 1 ; %x++ )
{
for ( %y = -1 ; %y <= 1 ; %y++ )
{
for ( %z = -1 ; %z <= 1 ; %z++ )
{
%rx = %px + %x;
%ry = %py + %y;
%rz = %pz + %z;

if ( %x == 0 && %y == 0 && %z == 0 )
{
continue;
}

if ( %rz > %th )  // Does this cause us to arrive on ground?
{
continue; // If so, don't screw with ground level; go to next iteration.
}

if ( %rz < 0 )     // Does this cause us to arrive below bedrock?
{
continue; // If so, don't cause index errors; go to next iteration.
}

if ( %rz > 255 )   // Does this cause us to arrive above world?
{   // (note: I'm not sure how this could happen)
continue; // If so, don't cause index errors; go to next iteration.
}

if ( strLen( getBlock( %rx, %ry, %rz ) ) ) // Is there already something here?
{
continue; // If so, don't overwrite it; go to next iteration.
}

if ( generatedPoint( %rx, %ry, %rz ) ) // Did we already generate something here ..
{ // .. which was destroyed by some force?
continue; // If so, don't generate it again; go to next iteration.
}

%dp = %bl - %z; // Determine distance to ground at current point.
%block = "";

if ( %dp < 3 )
{
%block = "dirt";

//if ( getRandom() <= 0.15 )
//{
// %block = "gravel";
//}
}
else
{
if ( %rz <= 7 )
{
%block = "smoothStone";
}
//else if ( %rz <= 10 )
//{
// %block = "lava";
//}
else
{
%block = "smoothStone";

//if ( getRandom() <= 0.1 )
//{
// %block = "gravel";
//}
//else
//{
// if ( %rz <= 63 && getRandom() <= 0.05 )
// {
// %block = "ironOre";
// }
// else if ( %rz <= 31 && getRandom() <= 0.05 )
// {
// %block = "goldOre";
// }
//}
}
}

setBlock( %rx, %ry, %rz, %block );
}
}
}
}

// Nether
function chunkSO::generateNether( %this )
{
%this.generateOverworld();
}

// Aether
function chunkSO::generateAether( %this )
{
%this.generateOverworld();
}

// The End
function chunkSO::generateTheEnd( %this )
{
%this.generateOverworld();
}