Majorly optimise block physics performance, also reduce memory usage of level physics undo buffer.

This commit is contained in:
UnknownShadow200 2016-02-28 14:46:15 +11:00
parent 0543cb1dd3
commit db2b4646ff
11 changed files with 185 additions and 122 deletions

View File

@ -192,8 +192,8 @@ namespace MCGalaxy.Commands
bool CheckBlockPhysics(Player p, long seconds, int i, Level.UndoPos undo) { bool CheckBlockPhysics(Player p, long seconds, int i, Level.UndoPos undo) {
byte b = p.level.GetTile(undo.location); byte b = p.level.GetTile(undo.location);
if (undo.timePerformed.AddSeconds(seconds) < DateTime.Now) DateTime time = Server.StartTime.AddSeconds(undo.timeDelta);
return false; if (time.AddSeconds(seconds) < DateTime.UtcNow) return false;
if (b == undo.newType || Block.Convert(b) == Block.water || Block.Convert(b) == Block.lava) { if (b == undo.newType || Block.Convert(b) == Block.water || Block.Convert(b) == Block.lava) {
ushort x, y, z; ushort x, y, z;

View File

@ -392,7 +392,7 @@ namespace MCGalaxy {
uP.location = b; uP.location = b;
uP.newType = type; uP.newExtType = extType; uP.newType = type; uP.newExtType = extType;
uP.oldType = oldBlock; uP.oldExtType = oldExtType; uP.oldType = oldBlock; uP.oldExtType = oldExtType;
uP.timePerformed = DateTime.Now; uP.timeDelta = (int)DateTime.UtcNow.Subtract(Server.StartTime).TotalSeconds;
if (currentUndo > Server.physUndo) { if (currentUndo > Server.physUndo) {
currentUndo = 0; currentUndo = 0;

View File

@ -128,16 +128,17 @@ namespace MCGalaxy {
if (physics == 5) { if (physics == 5) {
for (int i = 0; i < ListCheck.Count; i++) { for (int i = 0; i < ListCheck.Count; i++) {
Check C = ListCheck.Items[i]; Check C = ListCheck.Items[i];
try { IntToPos(C.b, out x, out y, out z);
try {
string info = C.data as string; string info = C.data as string;
if (info == null) info = ""; if (info == null) info = "";
IntToPos(C.b, out x, out y, out z);
if (PhysicsUpdate != null) if (PhysicsUpdate != null)
PhysicsUpdate(x, y, z, C.time, info, this); PhysicsUpdate(x, y, z, C.time, info, this);
if (info == "" || ExtraInfoPhysics.DoDoorsOnly(this, C, null)) if (info == "" || ExtraInfoPhysics.DoDoorsOnly(this, C, null))
DoorPhysics.Do(this, C); DoorPhysics.Do(this, C);
} catch { } catch {
listCheckExists.Set(x, y, z, false);
ListCheck.Remove(C); ListCheck.Remove(C);
} }
} }
@ -145,23 +146,25 @@ namespace MCGalaxy {
Random rand = new Random(); Random rand = new Random();
for (int i = 0; i < ListCheck.Count; i++) { for (int i = 0; i < ListCheck.Count; i++) {
Check C = ListCheck.Items[i]; Check C = ListCheck.Items[i];
try { IntToPos(C.b, out x, out y, out z);
IntToPos(C.b, out x, out y, out z); try {
string info = C.data as string; string info = C.data as string;
if (info == null) info = ""; if (info == null) info = "";
if (PhysicsUpdate != null) if (PhysicsUpdate != null)
PhysicsUpdate(x, y, z, C.time, info, this); PhysicsUpdate(x, y, z, C.time, info, this);
OnPhysicsUpdateEvent.Call(x, y, z, C.time, info, this); if (OnPhysicsUpdateEvent.events.Count > 0)
OnPhysicsUpdateEvent.Call(x, y, z, C.time, info, this);
if (info == "" || ExtraInfoPhysics.DoComplex(this, C, rand)) if (info == "" || ExtraInfoPhysics.DoComplex(this, C, rand))
DoNormalPhysics(x, y, z, rand, C); DoNormalPhysics(x, y, z, rand, C);
} catch { } catch {
listCheckExists.Set(x, y, z, false);
ListCheck.Remove(C); ListCheck.Remove(C);
} }
} }
} }
RemoveExpiredChecks();
ListCheck.RemoveAll(C => C.time == 255); //Remove all that are finished with 255 time
lastUpdate = ListUpdate.Count; lastUpdate = ListUpdate.Count;
for (int i = 0; i < ListUpdate.Count; i++) { for (int i = 0; i < ListUpdate.Count; i++) {
Update C = ListUpdate.Items[i]; Update C = ListUpdate.Items[i];
@ -173,7 +176,7 @@ namespace MCGalaxy {
Server.s.Log("Phys update issue"); Server.s.Log("Phys update issue");
} }
} }
ListUpdate.Clear(); ListUpdate.Clear(); listUpdateExists.Clear();
} catch (Exception e) { } catch (Exception e) {
Server.s.Log("Level physics error"); Server.s.Log("Level physics error");
Server.ErrorLog(e); Server.ErrorLog(e);
@ -415,7 +418,6 @@ namespace MCGalaxy {
ZombiePhysics.Do(this, C, rand); break; ZombiePhysics.Do(this, C, rand); break;
case Block.c4: case Block.c4:
Server.s.Log("Processing C4");
C4.C4s c4 = C4.Find(this, ((Player)C.data).c4circuitNumber); C4.C4s c4 = C4.Find(this, ((Player)C.data).c4circuitNumber);
if (c4 != null) { if (c4 != null) {
FillPos pos; pos.X = x; pos.Y = y; pos.Z = z; FillPos pos; pos.X = x; pos.Y = y; pos.Z = z;
@ -425,7 +427,6 @@ namespace MCGalaxy {
break; break;
case Block.c4det: case Block.c4det:
Server.s.Log("Processing C4 det");
C4.C4s c = C4.Find(this, ((Player)C.data).c4circuitNumber); C4.C4s c = C4.Find(this, ((Player)C.data).c4circuitNumber);
if (c != null) { if (c != null) {
c.detenator[0] = x; c.detenator[0] = x;
@ -440,16 +441,25 @@ namespace MCGalaxy {
DoorPhysics.Do(this, C); break; DoorPhysics.Do(this, C); break;
} }
} }
public void AddCheck(int b, bool overRide = false) { AddCheck(b, overRide, ""); } public void AddCheck(int b, bool overRide = false) { AddCheck(b, overRide, ""); }
public void AddCheck(int b, bool overRide, object data) { public void AddCheck(int b, bool overRide, object data) {
try { try {
int index = ListCheck.IndexOf(C => C.b == b); ushort x, y, z;
if (index < 0) { IntToPos(b, out x, out y, out z);
if (x >= Width || y >= Height || z >= Length) return;
if (!listCheckExists.Get(x, y, z)) {
ListCheck.Add(new Check(b, data)); //Adds block to list to be updated ListCheck.Add(new Check(b, data)); //Adds block to list to be updated
listCheckExists.Set(x, y, z, true);
} else if (overRide) { } else if (overRide) {
ListCheck.Items[index].data = data; return; Check[] items = ListCheck.Items;
int count = ListCheck.Count;
for (int i = 0; i < count; i++) {
if (items[i].b != b) continue;
items[i].data = data; return;
}
//Dont need to check physics here because if the list is active, then physics is active :) //Dont need to check physics here because if the list is active, then physics is active :)
} }
if (!physicssate && physics > 0) if (!physicssate && physics > 0)
@ -464,23 +474,25 @@ namespace MCGalaxy {
internal bool AddUpdate(int b, int type, bool overRide, object data) { internal bool AddUpdate(int b, int type, bool overRide, object data) {
try { try {
if (overRide) { ushort x, y, z;
ushort x, y, z; IntToPos(b, out x, out y, out z);
IntToPos(b, out x, out y, out z); if (x >= Width || y >= Height || z >= Length) return false;
AddCheck(b, true, data); //Dont need to check physics here....AddCheck will do that
if (overRide) {
AddCheck(b, true, data); //Dont need to check physics here....AddCheck will do that
string info = data as string; string info = data as string;
if (info == null) info = ""; if (info == null) info = "";
Blockchange(x, y, z, (byte)type, true, info); Blockchange(x, y, z, (byte)type, true, info);
return true; return true;
} }
if (!ListUpdate.Exists(C => C.b == b)) { if (!listUpdateExists.Get(x, y, z)) {
listUpdateExists.Set(x, y, z, true);
} else if (type == Block.sand || type == Block.gravel) { } else if (type == Block.sand || type == Block.gravel) {
ListUpdate.RemoveAll(C => C.b == b); RemoveUpdatesAtPos(b);
} else { } else {
return false; return false;
} }
ListUpdate.Add(new Update(b, (byte)type, data)); ListUpdate.Add(new Update(b, (byte)type, data));
if (!physicssate && physics > 0) if (!physicssate && physics > 0)
@ -492,12 +504,41 @@ namespace MCGalaxy {
return false; return false;
} }
} }
void RemoveExpiredChecks() {
Check[] items = ListCheck.Items;
int j = 0, count = ListCheck.Count;
ushort x, y, z;
for (int i = 0; i < count; i++) {
if (items[i].time == 255) {
IntToPos(items[i].b, out x, out y, out z);
listCheckExists.Set(x, y, z, false);
continue;
}
items[j] = items[i]; j++;
}
ListCheck.Items = items;
ListCheck.Count = j;
}
void RemoveUpdatesAtPos(int b) {
Update[] items = ListUpdate.Items;
int j = 0, count = ListUpdate.Count;
for (int i = 0; i < count; i++) {
if (items[j].b == b) continue;
items[j] = items[i]; j++;
}
ListUpdate.Items = items;
ListUpdate.Count = j;
}
public void ClearPhysics() { public void ClearPhysics() {
for (int i = 0; i < ListCheck.Count; i++ ) for (int i = 0; i < ListCheck.Count; i++ )
RevertPhysics(ListCheck.Items[i]); RevertPhysics(ListCheck.Items[i]);
ListCheck.Clear(); ListCheck.Clear(); listCheckExists.Clear();
ListUpdate.Clear(); ListUpdate.Clear(); listUpdateExists.Clear();
} }
void RevertPhysics(Check C) { void RevertPhysics(Check C) {
@ -541,22 +582,21 @@ namespace MCGalaxy {
internal void PhysAir(int b) { AirPhysics.PhysAir(this, b); } internal void PhysAir(int b) { AirPhysics.PhysAir(this, b); }
internal void PhysWater(int b, byte type) { internal void PhysWater(ushort x, ushort y, ushort z, byte type) {
if (b == -1) return; if (x >= Width || y >= Height || z >= Length) return;
ushort x, y, z;
IntToPos(b, out x, out y, out z);
if (Server.lava.active && Server.lava.map == this && Server.lava.InSafeZone(x, y, z)) if (Server.lava.active && Server.lava.map == this && Server.lava.InSafeZone(x, y, z))
return; return;
int b = x + (z * Width) + (y * Width * Length);
switch (blocks[b]) { switch (blocks[b]) {
case Block.air: case Block.air:
if (!PhysSpongeCheck(b)) AddUpdate(b, type); if (!CheckSpongeWater(x, y, z)) AddUpdate(b, type);
break; break;
case Block.lava: case Block.lava:
case Block.lava_fast: case Block.lava_fast:
case Block.activedeathlava: case Block.activedeathlava:
if (!PhysSpongeCheck(b)) AddUpdate(b, Block.rock); if (!CheckSpongeWater(x, y, z)) AddUpdate(b, Block.rock);
break; break;
case Block.shrub: case Block.shrub:
@ -564,7 +604,7 @@ namespace MCGalaxy {
case Block.redflower: case Block.redflower:
case Block.mushroom: case Block.mushroom:
case Block.redmushroom: case Block.redmushroom:
if (physics > 1 && physics != 5 && !PhysSpongeCheck(b)) if (physics > 1 && physics != 5 && !CheckSpongeWater(x, y, z))
AddUpdate(b, 0); //Adv physics kills flowers and mushrooms in water AddUpdate(b, 0); //Adv physics kills flowers and mushrooms in water
break; break;
@ -577,25 +617,24 @@ namespace MCGalaxy {
} }
} }
internal void PhysLava(int b, byte type) { internal void PhysLava(ushort x, ushort y, ushort z, byte type) {
if (b == -1) return; if (x >= Width || y >= Height || z >= Length) return;
ushort x, y, z;
IntToPos(b, out x, out y, out z);
if (Server.lava.active && Server.lava.map == this && Server.lava.InSafeZone(x, y, z)) if (Server.lava.active && Server.lava.map == this && Server.lava.InSafeZone(x, y, z))
return; return;
if (physics > 1 && physics != 5 && !PhysSpongeCheck(b, true) && blocks[b] >= 21 && blocks[b] <= 36) { int b = x + Width * (z + y * Length);
if (physics > 1 && physics != 5 && !CheckSpongeLava(x, y, z) && blocks[b] >= 21 && blocks[b] <= 36) {
AddUpdate(b, Block.air); return; AddUpdate(b, Block.air); return;
} // Adv physics destroys cloth } // Adv physics destroys cloth
switch (blocks[b]) { switch (blocks[b]) {
case Block.air: case Block.air:
if (!PhysSpongeCheck(b, true)) AddUpdate(b, type); if (!CheckSpongeLava(x, y, z)) AddUpdate(b, type);
break; break;
case Block.water: case Block.water:
case Block.activedeathwater: case Block.activedeathwater:
if (!PhysSpongeCheck(b, true)) AddUpdate(b, Block.rock); break; if (!CheckSpongeLava(x, y, z)) AddUpdate(b, Block.rock); break;
case Block.sand: case Block.sand:
if (physics > 1) { //Adv physics changes sand to glass next to lava if (physics > 1) { //Adv physics changes sand to glass next to lava
@ -616,7 +655,7 @@ namespace MCGalaxy {
case Block.mushroom: case Block.mushroom:
case Block.redmushroom: case Block.redmushroom:
if (physics > 1 && physics != 5) //Adv physics kills flowers and mushrooms plus wood in lava if (physics > 1 && physics != 5) //Adv physics kills flowers and mushrooms plus wood in lava
if (!PhysSpongeCheck(b, true)) AddUpdate(b, Block.air); if (!CheckSpongeLava(x, y, z)) AddUpdate(b, Block.air);
break; break;
default: default:
break; break;
@ -716,16 +755,33 @@ namespace MCGalaxy {
AddUpdate(bBelow, Block.stone); AddUpdate(bBelow, Block.stone);
} }
} }
internal bool PhysSpongeCheck(int b, bool lava = false) { internal bool CheckSpongeWater(ushort x, ushort y, ushort z) {
for (int y = -2; y <= +2; ++y) for (int yy = y - 2; yy <= y + 2; ++yy) {
for (int z = -2; z <= +2; ++z) if (yy < 0 || yy >= Height) continue;
for (int x = -2; x <= +2; ++x) for (int zz = z - 2; zz <= z + 2; ++zz) {
{ if (zz < 0 || zz >= Length) continue;
byte block = GetTile(IntOffset(b, x, y, z)); for (int xx = x - 2; xx <= x + 2; ++xx) {
if (block == Block.Zero) continue; if (xx < 0 || xx >= Width) continue;
if ((!lava && block == Block.sponge) || (lava && block == Block.lava_sponge)) if (blocks[xx + Width * (zz + yy * Length)] == Block.sponge)
return true; return true;
}
}
}
return false;
}
internal bool CheckSpongeLava(ushort x, ushort y, ushort z) {
for (int yy = y - 2; yy <= y + 2; ++yy) {
if (yy < 0 || yy >= Height) continue;
for (int zz = z - 2; zz <= z + 2; ++zz) {
if (zz < 0 || zz >= Length) continue;
for (int xx = x - 2; xx <= x + 2; ++xx) {
if (xx < 0 || xx >= Width) continue;
if (blocks[xx + Width * (zz + yy * Length)] == Block.lava_sponge)
return true;
}
}
} }
return false; return false;
} }

View File

@ -69,6 +69,7 @@ namespace MCGalaxy
public static bool cancelphysics; public static bool cancelphysics;
internal readonly FastList<Check> ListCheck = new FastList<Check>(); //A list of blocks that need to be updated internal readonly FastList<Check> ListCheck = new FastList<Check>(); //A list of blocks that need to be updated
internal readonly FastList<Update> ListUpdate = new FastList<Update>(); //A list of block to change after calculation internal readonly FastList<Update> ListUpdate = new FastList<Update>(); //A list of block to change after calculation
internal readonly SparseBitSet listCheckExists, listUpdateExists;
internal readonly Dictionary<int, sbyte> leaves = new Dictionary<int, sbyte>(); internal readonly Dictionary<int, sbyte> leaves = new Dictionary<int, sbyte>();
// Holds block state for leaf decay // Holds block state for leaf decay
@ -236,6 +237,8 @@ namespace MCGalaxy
spawnz = (ushort)(Length / 2); spawnz = (ushort)(Length / 2);
rotx = 0; rotx = 0;
roty = 0; roty = 0;
listCheckExists = new SparseBitSet(Width, Height, Length);
listUpdateExists = new SparseBitSet(Width, Height, Length);
//season = new SeasonsCore(this); //season = new SeasonsCore(this);
} }
@ -251,8 +254,8 @@ namespace MCGalaxy
Extras.Clear(); Extras.Clear();
liquids.Clear(); liquids.Clear();
leaves.Clear(); leaves.Clear();
ListCheck.Clear(); ListCheck.Clear(); listCheckExists.Clear();
ListUpdate.Clear(); ListUpdate.Clear(); listUpdateExists.Clear();
UndoBuffer.Clear(); UndoBuffer.Clear();
blockCache.Clear(); blockCache.Clear();
ZoneList.Clear(); ZoneList.Clear();
@ -429,10 +432,8 @@ namespace MCGalaxy
// Returns true if ListCheck does not already have an check in the position. // Returns true if ListCheck does not already have an check in the position.
// Useful for fireworks, which depend on two physics blocks being checked, one with extraInfo. // Useful for fireworks, which depend on two physics blocks being checked, one with extraInfo.
public bool CheckClear(ushort x, ushort y, ushort z) public bool CheckClear(ushort x, ushort y, ushort z) {
{ return x >= Width || y >= Height || z >= Length || !listCheckExists.Get(x, y, z);
int b = PosToInt(x, y, z);
return !ListCheck.Exists(C => C.b == b);
} }
public void Save(bool Override = false, bool clearPhysics = false) public void Save(bool Override = false, bool clearPhysics = false)
@ -744,7 +745,7 @@ namespace MCGalaxy
public int location; public int location;
public byte newType, newExtType; public byte newType, newExtType;
public byte oldType, oldExtType; public byte oldType, oldExtType;
public DateTime timePerformed; public int timeDelta;
} }
public struct Zone { public struct Zone {

View File

@ -151,8 +151,8 @@ namespace MCGalaxy.BlockPhysics {
int b1 = lvl.IntOffset(C.b, xx * 3, yy * 3, zz * 3); int b1 = lvl.IntOffset(C.b, xx * 3, yy * 3, zz * 3);
int b2 = lvl.IntOffset(C.b, xx * 2, yy * 2, zz * 2); int b2 = lvl.IntOffset(C.b, xx * 2, yy * 2, zz * 2);
bool unblocked = lvl.GetTile(b1) == Block.air && lvl.GetTile(b2) == Block.air && bool unblocked = lvl.GetTile(b1) == Block.air && lvl.GetTile(b2) == Block.air &&
!lvl.ListUpdate.Exists(u => u.b == b1) && !lvl.listUpdateExists.Get(x + xx * 3, y + yy * 3, z + zz * 3) &&
!lvl.ListUpdate.Exists(u => u.b == b2); !lvl.listUpdateExists.Get(x + xx * 2, y + yy * 2, z + zz * 2);
if (unblocked) { if (unblocked) {
lvl.AddUpdate(b1, Block.rockethead); lvl.AddUpdate(b1, Block.rockethead);
@ -166,8 +166,8 @@ namespace MCGalaxy.BlockPhysics {
int b1 = lvl.IntOffset(C.b, xx, yy + 1, zz); int b1 = lvl.IntOffset(C.b, xx, yy + 1, zz);
int b2 = lvl.IntOffset(C.b, xx, yy + 2, zz); int b2 = lvl.IntOffset(C.b, xx, yy + 2, zz);
bool unblocked = lvl.GetTile(b1) == Block.air && lvl.GetTile(b2) == Block.air && bool unblocked = lvl.GetTile(b1) == Block.air && lvl.GetTile(b2) == Block.air &&
!lvl.ListUpdate.Exists(u => u.b == b1) && !lvl.listUpdateExists.Get(x + xx, y + yy + 1, z + zz) &&
!lvl.ListUpdate.Exists(u => u.b == b2); !lvl.listUpdateExists.Get(x + xx, y + yy + 2, z + zz);
if (unblocked) { if (unblocked) {
lvl.AddUpdate(b2, Block.firework); lvl.AddUpdate(b2, Block.firework);

View File

@ -33,10 +33,10 @@ namespace MCGalaxy.BlockPhysics {
lvl.AddUpdate(lvl.PosToInt(x, (ushort)(y - 1), z), Block.magma); lvl.AddUpdate(lvl.PosToInt(x, (ushort)(y - 1), z), Block.magma);
} else if (below != Block.magma) { } else if (below != Block.magma) {
byte block = lvl.blocks[C.b]; byte block = lvl.blocks[C.b];
lvl.PhysLava(lvl.PosToInt((ushort)(x + 1), y, z), block); lvl.PhysLava((ushort)(x + 1), y, z, block);
lvl.PhysLava(lvl.PosToInt((ushort)(x - 1), y, z), block); lvl.PhysLava((ushort)(x - 1), y, z, block);
lvl.PhysLava(lvl.PosToInt(x, y, (ushort)(z + 1)), block); lvl.PhysLava(x, y, (ushort)(z + 1), block);
lvl.PhysLava(lvl.PosToInt(x, y, (ushort)(z - 1)), block); lvl.PhysLava(x, y, (ushort)(z - 1), block);
} }
if (lvl.physics <= 1 || C.time <= 10) return; if (lvl.physics <= 1 || C.time <= 10) return;
@ -70,10 +70,10 @@ namespace MCGalaxy.BlockPhysics {
lvl.AddUpdate(lvl.PosToInt(x, (ushort)(y - 1), z), Block.geyser); lvl.AddUpdate(lvl.PosToInt(x, (ushort)(y - 1), z), Block.geyser);
} else if (below != Block.geyser) { } else if (below != Block.geyser) {
byte block = lvl.blocks[C.b]; byte block = lvl.blocks[C.b];
lvl.PhysWater(lvl.PosToInt((ushort)(x + 1), y, z), block); lvl.PhysWater((ushort)(x + 1), y, z, block);
lvl.PhysWater(lvl.PosToInt((ushort)(x - 1), y, z), block); lvl.PhysWater((ushort)(x - 1), y, z, block);
lvl.PhysWater(lvl.PosToInt(x, y, (ushort)(z + 1)), block); lvl.PhysWater(x, y, (ushort)(z + 1), block);
lvl.PhysWater(lvl.PosToInt(x, y, (ushort)(z - 1)), block); lvl.PhysWater(x, y, (ushort)(z - 1), block);
} }
if (lvl.physics <= 1 || C.time <= 10) return; if (lvl.physics <= 1 || C.time <= 10) return;
@ -116,10 +116,10 @@ namespace MCGalaxy.BlockPhysics {
break; break;
default: default:
byte block = lvl.blocks[C.b]; byte block = lvl.blocks[C.b];
lvl.PhysWater(lvl.PosToInt((ushort)(x + 1), y, z), block); lvl.PhysWater((ushort)(x + 1), y, z, block);
lvl.PhysWater(lvl.PosToInt((ushort)(x - 1), y, z), block); lvl.PhysWater((ushort)(x - 1), y, z, block);
lvl.PhysWater(lvl.PosToInt(x, y, (ushort)(z + 1)),block); lvl.PhysWater(x, y, (ushort)(z + 1),block);
lvl.PhysWater(lvl.PosToInt(x, y, (ushort)(z - 1)), block); lvl.PhysWater(x, y, (ushort)(z - 1), block);
if (!(C.data is string) || !((string)C.data).Contains("wait")) if (!(C.data is string) || !((string)C.data).Contains("wait"))
C.time = 255; C.time = 255;
break; break;
@ -145,10 +145,10 @@ namespace MCGalaxy.BlockPhysics {
break; break;
default: default:
byte block = lvl.blocks[C.b]; byte block = lvl.blocks[C.b];
lvl.PhysLava(lvl.PosToInt((ushort)(x + 1), y, z), block); lvl.PhysLava((ushort)(x + 1), y, z, block);
lvl.PhysLava(lvl.PosToInt((ushort)(x - 1), y, z), block); lvl.PhysLava((ushort)(x - 1), y, z, block);
lvl.PhysLava(lvl.PosToInt(x, y, (ushort)(z + 1)),block); lvl.PhysLava(x, y, (ushort)(z + 1),block);
lvl.PhysLava(lvl.PosToInt(x, y, (ushort)(z - 1)), block); lvl.PhysLava(x, y, (ushort)(z - 1), block);
if (!(C.data is string) || !((string)C.data).Contains("wait")) if (!(C.data is string) || !((string)C.data).Contains("wait"))
C.time = 255; C.time = 255;
break; break;

View File

@ -152,7 +152,7 @@ namespace MCGalaxy.BlockPhysics {
// Not setting drop = false can cause occasional leftover blocks, since C.extraInfo is emptied, so // Not setting drop = false can cause occasional leftover blocks, since C.extraInfo is emptied, so
// drop can generate another block with no dissipate/explode information. // drop can generate another block with no dissipate/explode information.
if (args.Dissipate && rand.Next(1, 100) <= args.DissipateNum) { if (args.Dissipate && rand.Next(1, 100) <= args.DissipateNum) {
if (!lvl.ListUpdate.Exists(Update => Update.b == C.b)) { if (!lvl.listUpdateExists.Get(x, y, z)) {
lvl.AddUpdate(C.b, Block.air); lvl.AddUpdate(C.b, Block.air);
C.data = ""; C.data = "";
args.Drop = false; args.Drop = false;

View File

@ -36,7 +36,7 @@ namespace MCGalaxy.BlockPhysics {
if (keepGoing) { if (keepGoing) {
int bAbove = lvl.PosToInt(x, (ushort)(y + 1), z); int bAbove = lvl.PosToInt(x, (ushort)(y + 1), z);
bool unblocked = !lvl.ListUpdate.Exists(u => u.b == bAbove); bool unblocked = bAbove < 0 || !lvl.listUpdateExists.Get(x, y + 1, z);
if (unblocked) { if (unblocked) {
lvl.AddUpdate(bAbove, Block.firework, false); lvl.AddUpdate(bAbove, Block.firework, false);
lvl.AddUpdate(C.b, Block.lavastill, false, "wait 1 dissipate 100"); lvl.AddUpdate(C.b, Block.lavastill, false, "wait 1 dissipate 100");

View File

@ -22,6 +22,7 @@ namespace MCGalaxy.BlockPhysics {
public static class LiquidPhysics { public static class LiquidPhysics {
const StringComparison comp = StringComparison.Ordinal;
public static void DoWater(Level lvl, Check C, Random rand) { public static void DoWater(Level lvl, Check C, Random rand) {
if (lvl.finite) { if (lvl.finite) {
lvl.liquids.Remove(C.b); lvl.liquids.Remove(C.b);
@ -65,7 +66,7 @@ namespace MCGalaxy.BlockPhysics {
ushort x, y, z; ushort x, y, z;
lvl.IntToPos(C.b, out x, out y, out z); lvl.IntToPos(C.b, out x, out y, out z);
if (!lvl.PhysSpongeCheck(C.b)) { if (!lvl.CheckSpongeWater(x, y, z)) {
if (!lvl.liquids.TryGetValue(C.b, out blocked)) { if (!lvl.liquids.TryGetValue(C.b, out blocked)) {
blocked = new bool[5]; blocked = new bool[5];
lvl.liquids.Add(C.b, blocked); lvl.liquids.Add(C.b, blocked);
@ -77,23 +78,23 @@ namespace MCGalaxy.BlockPhysics {
} }
if (!blocked[0] && rand.Next(4) == 0) { if (!blocked[0] && rand.Next(4) == 0) {
lvl.PhysWater(lvl.PosToInt((ushort)(x + 1), y, z), block); lvl.PhysWater((ushort)(x + 1), y, z, block);
blocked[0] = true; blocked[0] = true;
} }
if (!blocked[1] && rand.Next(4) == 0) { if (!blocked[1] && rand.Next(4) == 0) {
lvl.PhysWater(lvl.PosToInt((ushort)(x - 1), y, z), block); lvl.PhysWater((ushort)(x - 1), y, z, block);
blocked[1] = true; blocked[1] = true;
} }
if (!blocked[2] && rand.Next(4) == 0) { if (!blocked[2] && rand.Next(4) == 0) {
lvl.PhysWater(lvl.PosToInt(x, y, (ushort)(z + 1)), block); lvl.PhysWater(x, y, (ushort)(z + 1), block);
blocked[2] = true; blocked[2] = true;
} }
if (!blocked[3] && rand.Next(4) == 0) { if (!blocked[3] && rand.Next(4) == 0) {
lvl.PhysWater(lvl.PosToInt(x, y, (ushort)(z - 1)), block); lvl.PhysWater(x, y, (ushort)(z - 1), block);
blocked[3] = true; blocked[3] = true;
} }
if (!blocked[4] && rand.Next(4) == 0) { if (!blocked[4] && rand.Next(4) == 0) {
lvl.PhysWater(lvl.PosToInt(x, (ushort)(y - 1), z), block); lvl.PhysWater(x, (ushort)(y - 1), z, block);
blocked[4] = true; blocked[4] = true;
} }
@ -111,11 +112,11 @@ namespace MCGalaxy.BlockPhysics {
lvl.liquids.TryGetValue(C.b, out blocked); lvl.liquids.TryGetValue(C.b, out blocked);
lvl.AddUpdate(C.b, Block.air); lvl.AddUpdate(C.b, Block.air);
if (((string)C.data).IndexOf("wait") == -1) if (((string)C.data).IndexOf("wait", comp) == -1)
C.time = 255; C.time = 255;
} }
if (((string)C.data).IndexOf("wait") == -1 && blocked != null) if (((string)C.data).IndexOf("wait", comp) == -1 && blocked != null)
if (blocked[0] && blocked[1] && blocked[2] && blocked[3] && blocked[4]) if (blocked[0] && blocked[1] && blocked[2] && blocked[3] && blocked[4])
{ {
lvl.liquids.Remove(C.b); lvl.liquids.Remove(C.b);
@ -128,21 +129,21 @@ namespace MCGalaxy.BlockPhysics {
ushort x, y, z; ushort x, y, z;
lvl.IntToPos(C.b, out x, out y, out z); lvl.IntToPos(C.b, out x, out y, out z);
if (!lvl.PhysSpongeCheck(C.b)) { if (!lvl.CheckSpongeWater(x, y, z)) {
byte block = lvl.blocks[C.b]; byte block = lvl.blocks[C.b];
if (lvl.GetTile(x, (ushort)(y + 1), z) != Block.Zero) { if (lvl.GetTile(x, (ushort)(y + 1), z) != Block.Zero) {
lvl.PhysSandCheck(lvl.PosToInt(x, (ushort)(y + 1), z)); lvl.PhysSandCheck(lvl.PosToInt(x, (ushort)(y + 1), z));
} }
lvl.PhysWater(lvl.PosToInt((ushort)(x + 1), y, z), block); lvl.PhysWater((ushort)(x + 1), y, z, block);
lvl.PhysWater(lvl.PosToInt((ushort)(x - 1), y, z), block); lvl.PhysWater((ushort)(x - 1), y, z, block);
lvl.PhysWater(lvl.PosToInt(x, y, (ushort)(z + 1)), block); lvl.PhysWater(x, y, (ushort)(z + 1), block);
lvl.PhysWater(lvl.PosToInt(x, y, (ushort)(z - 1)), block); lvl.PhysWater(x, y, (ushort)(z - 1), block);
lvl.PhysWater(lvl.PosToInt(x, (ushort)(y - 1), z), block); lvl.PhysWater(x, (ushort)(y - 1), z, block);
} else { //was placed near sponge } else { //was placed near sponge
lvl.AddUpdate(C.b, Block.air); lvl.AddUpdate(C.b, Block.air);
} }
if (((string)C.data).IndexOf("wait") == -1) if (((string)C.data).IndexOf("wait", comp) == -1)
C.time = 255; C.time = 255;
} }
@ -158,7 +159,7 @@ namespace MCGalaxy.BlockPhysics {
case Block.lava: case Block.lava:
case Block.lava_fast: case Block.lava_fast:
case Block.activedeathlava: case Block.activedeathlava:
if (!lvl.PhysSpongeCheck(b)) return false; if (!lvl.CheckSpongeWater(x, y, z)) return false;
break; break;
case Block.shrub: case Block.shrub:
@ -166,7 +167,7 @@ namespace MCGalaxy.BlockPhysics {
case Block.redflower: case Block.redflower:
case Block.mushroom: case Block.mushroom:
case Block.redmushroom: case Block.redmushroom:
if (lvl.physics > 1 && !lvl.PhysSpongeCheck(b)) return false; if (lvl.physics > 1 && !lvl.CheckSpongeWater(x, y, z)) return false;
break; break;
case Block.sand: case Block.sand:
@ -182,7 +183,7 @@ namespace MCGalaxy.BlockPhysics {
ushort x, y, z; ushort x, y, z;
lvl.IntToPos(C.b, out x, out y, out z); lvl.IntToPos(C.b, out x, out y, out z);
if (!lvl.PhysSpongeCheck(C.b, true)) { if (!lvl.CheckSpongeLava(x, y, z)) {
C.time = (byte)rand.Next(3); C.time = (byte)rand.Next(3);
if (!lvl.liquids.TryGetValue(C.b, out blocked)) { if (!lvl.liquids.TryGetValue(C.b, out blocked)) {
blocked = new bool[5]; blocked = new bool[5];
@ -191,23 +192,23 @@ namespace MCGalaxy.BlockPhysics {
byte block = lvl.blocks[C.b]; byte block = lvl.blocks[C.b];
if (!blocked[0] && rand.Next(4) == 0) { if (!blocked[0] && rand.Next(4) == 0) {
lvl.PhysLava(lvl.PosToInt((ushort)(x + 1), y, z), block); lvl.PhysLava((ushort)(x + 1), y, z, block);
blocked[0] = true; blocked[0] = true;
} }
if (!blocked[1] && rand.Next(4) == 0) { if (!blocked[1] && rand.Next(4) == 0) {
lvl.PhysLava(lvl.PosToInt((ushort)(x - 1), y, z), block); lvl.PhysLava((ushort)(x - 1), y, z, block);
blocked[1] = true; blocked[1] = true;
} }
if (!blocked[2] && rand.Next(4) == 0) { if (!blocked[2] && rand.Next(4) == 0) {
lvl.PhysLava(lvl.PosToInt(x, y, (ushort)(z + 1)), block); lvl.PhysLava(x, y, (ushort)(z + 1), block);
blocked[2] = true; blocked[2] = true;
} }
if (!blocked[3] && rand.Next(4) == 0) { if (!blocked[3] && rand.Next(4) == 0) {
lvl.PhysLava(lvl.PosToInt(x, y, (ushort)(z - 1)), block); lvl.PhysLava(x, y, (ushort)(z - 1), block);
blocked[3] = true; blocked[3] = true;
} }
if (!blocked[4] && rand.Next(4) == 0) { if (!blocked[4] && rand.Next(4) == 0) {
lvl.PhysLava(lvl.PosToInt(x, (ushort)(y - 1), z), block); lvl.PhysLava(x, (ushort)(y - 1), z, block);
blocked[4] = true; blocked[4] = true;
} }
@ -224,11 +225,11 @@ namespace MCGalaxy.BlockPhysics {
} else { //was placed near sponge } else { //was placed near sponge
lvl.liquids.TryGetValue(C.b, out blocked); lvl.liquids.TryGetValue(C.b, out blocked);
lvl.AddUpdate(C.b, Block.air); lvl.AddUpdate(C.b, Block.air);
if (!checkWait || ((string)C.data).IndexOf("wait") == -1) if (!checkWait || ((string)C.data).IndexOf("wait", comp) == -1)
C.time = 255; C.time = 255;
} }
if (blocked != null && (!checkWait || ((string)C.data).IndexOf("wait") == -1)) if (blocked != null && (!checkWait || ((string)C.data).IndexOf("wait", comp) == -1))
if (blocked[0] && blocked[1] && blocked[2] && blocked[3] && blocked[4]) if (blocked[0] && blocked[1] && blocked[2] && blocked[3] && blocked[4])
{ {
lvl.liquids.Remove(C.b); lvl.liquids.Remove(C.b);
@ -241,18 +242,18 @@ namespace MCGalaxy.BlockPhysics {
ushort x, y, z; ushort x, y, z;
lvl.IntToPos(C.b, out x, out y, out z); lvl.IntToPos(C.b, out x, out y, out z);
if (!lvl.PhysSpongeCheck(C.b, true)) { if (!lvl.CheckSpongeLava(x, y, z)) {
byte block = lvl.blocks[C.b]; byte block = lvl.blocks[C.b];
lvl.PhysLava(lvl.PosToInt((ushort)(x + 1), y, z), block); lvl.PhysLava((ushort)(x + 1), y, z, block);
lvl.PhysLava(lvl.PosToInt((ushort)(x - 1), y, z), block); lvl.PhysLava((ushort)(x - 1), y, z, block);
lvl.PhysLava(lvl.PosToInt(x, y, (ushort)(z + 1)), block); lvl.PhysLava(x, y, (ushort)(z + 1), block);
lvl.PhysLava(lvl.PosToInt(x, y, (ushort)(z - 1)), block); lvl.PhysLava(x, y, (ushort)(z - 1), block);
lvl.PhysLava(lvl.PosToInt(x, (ushort)(y - 1), z), block); lvl.PhysLava(x, (ushort)(y - 1), z, block);
} else { //was placed near sponge } else { //was placed near sponge
lvl.AddUpdate(C.b, Block.air); lvl.AddUpdate(C.b, Block.air);
} }
if (!checkWait || ((string)C.data).IndexOf("wait") == -1) if (!checkWait || ((string)C.data).IndexOf("wait", comp) == -1)
C.time = 255; C.time = 255;
} }
@ -264,7 +265,7 @@ namespace MCGalaxy.BlockPhysics {
return true; return true;
if (lvl.physics > 1 && lvl.blocks[b] >= Block.red && lvl.blocks[b] <= Block.white if (lvl.physics > 1 && lvl.blocks[b] >= Block.red && lvl.blocks[b] <= Block.white
&& !lvl.PhysSpongeCheck(b, true)) && !lvl.CheckSpongeLava(x, y, z))
return false; // Adv physics destroys cloth return false; // Adv physics destroys cloth
switch (lvl.blocks[b]) { switch (lvl.blocks[b]) {
@ -273,7 +274,7 @@ namespace MCGalaxy.BlockPhysics {
case Block.water: case Block.water:
case Block.activedeathwater: case Block.activedeathwater:
if (!lvl.PhysSpongeCheck(b, true)) return false; if (!lvl.CheckSpongeLava(x, y, z)) return false;
break; break;
case Block.sand: case Block.sand:
@ -288,7 +289,7 @@ namespace MCGalaxy.BlockPhysics {
case Block.redflower: case Block.redflower:
case Block.mushroom: case Block.mushroom:
case Block.redmushroom: case Block.redmushroom:
if (lvl.physics > 1 && !lvl.PhysSpongeCheck(b, true)) return false; if (lvl.physics > 1 && !lvl.CheckSpongeLava(x, y, z)) return false;
break; break;
} }
return true; return true;

View File

@ -38,7 +38,8 @@ namespace MCGalaxy.BlockPhysics {
int headIndex = lvl.PosToInt((ushort)(x - cx), (ushort)(y - cy), (ushort)(z - cz)); int headIndex = lvl.PosToInt((ushort)(x - cx), (ushort)(y - cy), (ushort)(z - cz));
byte rocketHead = headIndex < 0 ? Block.Zero : lvl.blocks[headIndex]; byte rocketHead = headIndex < 0 ? Block.Zero : lvl.blocks[headIndex];
bool unblocked = !lvl.ListUpdate.Exists(u => u.b == headIndex || u.b == C.b); bool unblocked = !lvl.listUpdateExists.Get(x, y, z) &&
(headIndex < 0 || !lvl.listUpdateExists.Get(x - cx, y - cy, z - cz));
if (unblocked && (rocketHead == Block.air || rocketHead == Block.rocketstart)) { if (unblocked && (rocketHead == Block.air || rocketHead == Block.rocketstart)) {
lvl.AddUpdate(headIndex, Block.rockethead); lvl.AddUpdate(headIndex, Block.rockethead);

View File

@ -62,6 +62,10 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Content Include="Galaxy.ico" /> <Content Include="Galaxy.ico" />
<Content Include="ProfilingSessions\Session20160228_124429.sdps" />
<Content Include="ProfilingSessions\Session20160228_131348.sdps" />
<Content Include="ProfilingSessions\Session20160228_135632.sdps" />
<Content Include="ProfilingSessions\Session20160228_135946.sdps" />
</ItemGroup> </ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. <!-- To modify your build process, add your task inside one of the targets below and uncomment it.