Modularise level database interaction code.

This commit is contained in:
UnknownShadow200 2016-06-30 19:37:29 +10:00
parent 46e1b7bffe
commit ff2b697805
4 changed files with 198 additions and 176 deletions

192
Levels/Level.DB.cs Normal file
View File

@ -0,0 +1,192 @@
/*
Copyright 2010 MCSharp team (Modified for use with MCZall/MCLawl/MCGalaxy)
Dual-licensed under the Educational Community License, Version 2.0 and
the GNU General Public License, Version 3 (the "Licenses"); you may
not use this file except in compliance with the Licenses. You may
obtain a copy of the Licenses at
http://www.opensource.org/licenses/ecl2.php
http://www.gnu.org/licenses/gpl-3.0.html
Unless required by applicable law or agreed to in writing,
software distributed under the Licenses are distributed on an "AS IS"
BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
or implied. See the Licenses for the specific language governing
permissions and limitations under the Licenses.
*/
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using MCGalaxy.SQL;
using MCGalaxy.SQL.Native;
namespace MCGalaxy {
public sealed partial class Level : IDisposable {
public unsafe void saveChanges() {
if (blockCache.Count == 0) return;
if (!UseBlockDB) { blockCache.Clear(); return; }
List<BlockPos> tempCache = blockCache;
string date = new String('-', 19); //yyyy-mm-dd hh:mm:ss
fixed (char* ptr = date) {
ptr[4] = '-'; ptr[7] = '-'; ptr[10] = ' '; ptr[13] = ':'; ptr[16] = ':';
using (BulkTransaction bulk = BulkTransaction.CreateNative())
DoSaveChanges(tempCache, ptr, date, bulk);
}
tempCache.Clear();
blockCache = new List<BlockPos>();
Server.s.Log("Saved BlockDB changes for:" + name, true);
}
unsafe bool DoSaveChanges(List<BlockPos> tempCache, char* ptr, string date,
BulkTransaction transaction) {
string template = "INSERT INTO `Block" + name +
"` (Username, TimePerformed, X, Y, Z, type, deleted) VALUES (@Name, @Time, @X, @Y, @Z, @Tile, @Del)";
ushort x, y, z;
IDbCommand cmd = BulkTransaction.CreateCommand(template, transaction);
if (cmd == null) return false;
IDataParameter nameP = transaction.CreateParam("@Name", DbType.AnsiStringFixedLength); cmd.Parameters.Add(nameP);
IDataParameter timeP = transaction.CreateParam("@Time", DbType.AnsiStringFixedLength); cmd.Parameters.Add(timeP);
IDataParameter xP = transaction.CreateParam("@X", DbType.UInt16); cmd.Parameters.Add(xP);
IDataParameter yP = transaction.CreateParam("@Y", DbType.UInt16); cmd.Parameters.Add(yP);
IDataParameter zP = transaction.CreateParam("@Z", DbType.UInt16); cmd.Parameters.Add(zP);
IDataParameter tileP = transaction.CreateParam("@Tile", DbType.Byte); cmd.Parameters.Add(tileP);
IDataParameter delP = transaction.CreateParam("@Del", DbType.Boolean); cmd.Parameters.Add(delP);
bool isNative = transaction is NativeBulkTransaction;
for (int i = 0; i < tempCache.Count; i++) {
BlockPos bP = tempCache[i];
IntToPos(bP.index, out x, out y, out z);
DateTime time = Server.StartTimeLocal.AddTicks((bP.flags >> 2) * TimeSpan.TicksPerSecond);
MakeInt(time.Year, 4, 0, ptr); MakeInt(time.Month, 2, 5, ptr); MakeInt(time.Day, 2, 8, ptr);
MakeInt(time.Hour, 2, 11, ptr); MakeInt(time.Minute, 2, 14, ptr); MakeInt(time.Second, 2, 17, ptr);
// For NativeParameter, we make the optimisation of avoiding boxing primitive types.
if (!isNative) {
nameP.Value = bP.name;
timeP.Value = date;
xP.Value = x; yP.Value = y; zP.Value = z;
tileP.Value = (bP.flags & 2) != 0 ? Block.custom_block : bP.rawType;
delP.Value = (bP.flags & 1) != 0;
} else {
((NativeParameter)nameP).SetString(bP.name);
((NativeParameter)timeP).SetString(date);
((NativeParameter)xP).U16Value = x;
((NativeParameter)yP).U16Value = y;
((NativeParameter)zP).U16Value = z;
((NativeParameter)tileP).U8Value = (bP.flags & 2) != 0 ? Block.custom_block : bP.rawType;
((NativeParameter)delP).BoolValue = (bP.flags & 1) != 0;
}
if (!BulkTransaction.Execute(template, cmd)) {
cmd.Dispose();
cmd.Parameters.Clear();
transaction.Rollback(); return false;
}
}
cmd.Dispose();
cmd.Parameters.Clear();
transaction.Commit();
return true;
}
unsafe static void MakeInt(int value, int chars, int offset, char* ptr) {
for (int i = 0; i < chars; i++, value /= 10) {
char c = (char)('0' + (value % 10));
ptr[offset + (chars - 1 - i)] = c;
}
}
const string createBlock =
@"CREATE TABLE if not exists `Block{0}` (
Username CHAR(20),
TimePerformed DATETIME,
X SMALLINT UNSIGNED,
Y SMALLINT UNSIGNED,
Z SMALLINT UNSIGNED,
Type TINYINT UNSIGNED,
Deleted {1})";
const string createPortals =
@"CREATE TABLE if not exists `Portals{0}` (
EntryX SMALLINT UNSIGNED,
EntryY SMALLINT UNSIGNED,
EntryZ SMALLINT UNSIGNED,
ExitMap CHAR(20),
ExitX SMALLINT UNSIGNED,
ExitY SMALLINT UNSIGNED,
ExitZ SMALLINT UNSIGNED)";
const string createMessages =
@"CREATE TABLE if not exists `Messages{0}` (
X SMALLINT UNSIGNED,
Y SMALLINT UNSIGNED,
Z SMALLINT UNSIGNED,
Message CHAR(255))";
const string createZones =
@"CREATE TABLE if not exists `Zone{0}` (
SmallX SMALLINT UNSIGNED,
SmallY SMALLINT UNSIGNED,
SmallZ SMALLINT UNSIGNED,
BigX SMALLINT UNSIGNED,
BigY SMALLINT UNSIGNED,
BigZ SMALLINT UNSIGNED,
Owner VARCHAR(20))";
public static void CreateLeveldb(string givenName) {
Database.executeQuery(String.Format(createBlock, givenName, Server.useMySQL ? "BOOL" : "INT"));
Database.executeQuery(String.Format(createPortals, givenName));
Database.executeQuery(String.Format(createMessages, givenName));
Database.executeQuery(String.Format(createZones, givenName));
}
static void LoadZones(Level level, string name) {
using (DataTable table = Database.fillData("SELECT * FROM `Zone" + name + "`")) {
Zone Zn;
foreach (DataRow row in table.Rows) {
Zn.smallX = ushort.Parse(row["SmallX"].ToString());
Zn.smallY = ushort.Parse(row["SmallY"].ToString());
Zn.smallZ = ushort.Parse(row["SmallZ"].ToString());
Zn.bigX = ushort.Parse(row["BigX"].ToString());
Zn.bigY = ushort.Parse(row["BigY"].ToString());
Zn.bigZ = ushort.Parse(row["BigZ"].ToString());
Zn.Owner = row["Owner"].ToString();
level.ZoneList.Add(Zn);
}
}
}
static void LoadMetadata(Level level, string name) {
using (DataTable table = Database.fillData("SELECT * FROM `Portals" + name + "`")) {
foreach (DataRow row in table.Rows) {
byte tile = level.GetTile(ushort.Parse(row["EntryX"].ToString()),
ushort.Parse(row["EntryY"].ToString()),
ushort.Parse(row["EntryZ"].ToString()));
if (Block.portal(tile)) continue;
Database.executeQuery("DELETE FROM `Portals" + name + "` WHERE EntryX=" + row["EntryX"]
+ " AND EntryY=" + row["EntryY"] + " AND EntryZ=" + row["EntryZ"]);
}
}
using (DataTable table = Database.fillData("SELECT * FROM `Messages" + name + "`")) {
foreach (DataRow row in table.Rows) {
byte tile = level.GetTile(ushort.Parse(row["X"].ToString()),
ushort.Parse(row["Y"].ToString()),
ushort.Parse(row["Z"].ToString()));
if (Block.mb(tile)) continue;
//givenName is safe against SQL injections, it gets checked in CmdLoad.cs
Database.executeQuery("DELETE FROM `Messages" + name + "` WHERE X=" +
row["X"] + " AND Y=" + row["Y"] + " AND Z=" + row["Z"]);
}
}
}
}
}

View File

@ -451,85 +451,7 @@ namespace MCGalaxy
PlayerActions.ChangeMap(p, Server.mainLevel.name); PlayerActions.ChangeMap(p, Server.mainLevel.name);
} }
} }
} }
public unsafe void saveChanges() {
if (blockCache.Count == 0) return;
if (!UseBlockDB) { blockCache.Clear(); return; }
List<BlockPos> tempCache = blockCache;
string date = new String('-', 19); //yyyy-mm-dd hh:mm:ss
fixed (char* ptr = date) {
ptr[4] = '-'; ptr[7] = '-'; ptr[10] = ' '; ptr[13] = ':'; ptr[16] = ':';
using (BulkTransaction bulk = BulkTransaction.CreateNative())
DoSaveChanges(tempCache, ptr, date, bulk);
}
tempCache.Clear();
blockCache = new List<BlockPos>();
Server.s.Log("Saved BlockDB changes for:" + name, true);
}
unsafe bool DoSaveChanges(List<BlockPos> tempCache, char* ptr, string date,
BulkTransaction transaction) {
string template = "INSERT INTO `Block" + name +
"` (Username, TimePerformed, X, Y, Z, type, deleted) VALUES (@Name, @Time, @X, @Y, @Z, @Tile, @Del)";
ushort x, y, z;
IDbCommand cmd = BulkTransaction.CreateCommand(template, transaction);
if (cmd == null) return false;
IDataParameter nameP = transaction.CreateParam("@Name", DbType.AnsiStringFixedLength); cmd.Parameters.Add(nameP);
IDataParameter timeP = transaction.CreateParam("@Time", DbType.AnsiStringFixedLength); cmd.Parameters.Add(timeP);
IDataParameter xP = transaction.CreateParam("@X", DbType.UInt16); cmd.Parameters.Add(xP);
IDataParameter yP = transaction.CreateParam("@Y", DbType.UInt16); cmd.Parameters.Add(yP);
IDataParameter zP = transaction.CreateParam("@Z", DbType.UInt16); cmd.Parameters.Add(zP);
IDataParameter tileP = transaction.CreateParam("@Tile", DbType.Byte); cmd.Parameters.Add(tileP);
IDataParameter delP = transaction.CreateParam("@Del", DbType.Boolean); cmd.Parameters.Add(delP);
bool isNative = transaction is NativeBulkTransaction;
for (int i = 0; i < tempCache.Count; i++) {
BlockPos bP = tempCache[i];
IntToPos(bP.index, out x, out y, out z);
DateTime time = Server.StartTimeLocal.AddTicks((bP.flags >> 2) * TimeSpan.TicksPerSecond);
MakeInt(time.Year, 4, 0, ptr); MakeInt(time.Month, 2, 5, ptr); MakeInt(time.Day, 2, 8, ptr);
MakeInt(time.Hour, 2, 11, ptr); MakeInt(time.Minute, 2, 14, ptr); MakeInt(time.Second, 2, 17, ptr);
// For NativeParameter, we make the optimisation of avoiding boxing primitive types.
if (!isNative) {
nameP.Value = bP.name;
timeP.Value = date;
xP.Value = x; yP.Value = y; zP.Value = z;
tileP.Value = (bP.flags & 2) != 0 ? Block.custom_block : bP.rawType;
delP.Value = (bP.flags & 1) != 0;
} else {
((NativeParameter)nameP).SetString(bP.name);
((NativeParameter)timeP).SetString(date);
((NativeParameter)xP).U16Value = x;
((NativeParameter)yP).U16Value = y;
((NativeParameter)zP).U16Value = z;
((NativeParameter)tileP).U8Value = (bP.flags & 2) != 0 ? Block.custom_block : bP.rawType;
((NativeParameter)delP).BoolValue = (bP.flags & 1) != 0;
}
if (!BulkTransaction.Execute(template, cmd)) {
cmd.Dispose();
cmd.Parameters.Clear();
transaction.Rollback(); return false;
}
}
cmd.Dispose();
cmd.Parameters.Clear();
transaction.Commit();
return true;
}
unsafe static void MakeInt(int value, int chars, int offset, char* ptr) {
for (int i = 0; i < chars; i++, value /= 10) {
char c = (char)('0' + (value % 10));
ptr[offset + (chars - 1 - i)] = c;
}
}
/// <summary> Returns whether the given coordinates are insides the boundaries of this level. </summary> /// <summary> Returns whether the given coordinates are insides the boundaries of this level. </summary>
public bool InBound(ushort x, ushort y, ushort z) { public bool InBound(ushort x, ushort y, ushort z) {
@ -646,50 +568,6 @@ namespace MCGalaxy
} }
} }
const string createBlock =
@"CREATE TABLE if not exists `Block{0}` (
Username CHAR(20),
TimePerformed DATETIME,
X SMALLINT UNSIGNED,
Y SMALLINT UNSIGNED,
Z SMALLINT UNSIGNED,
Type TINYINT UNSIGNED,
Deleted {1})";
const string createPortals =
@"CREATE TABLE if not exists `Portals{0}` (
EntryX SMALLINT UNSIGNED,
EntryY SMALLINT UNSIGNED,
EntryZ SMALLINT UNSIGNED,
ExitMap CHAR(20),
ExitX SMALLINT UNSIGNED,
ExitY SMALLINT UNSIGNED,
ExitZ SMALLINT UNSIGNED)";
const string createMessages =
@"CREATE TABLE if not exists `Messages{0}` (
X SMALLINT UNSIGNED,
Y SMALLINT UNSIGNED,
Z SMALLINT UNSIGNED,
Message CHAR(255))";
const string createZones =
@"CREATE TABLE if not exists `Zone{0}` (
SmallX SMALLINT UNSIGNED,
SmallY SMALLINT UNSIGNED,
SmallZ SMALLINT UNSIGNED,
BigX SMALLINT UNSIGNED,
BigY SMALLINT UNSIGNED,
BigZ SMALLINT UNSIGNED,
Owner VARCHAR(20))";
public static void CreateLeveldb(string givenName) {
Database.executeQuery(String.Format(createBlock, givenName, Server.useMySQL ? "BOOL" : "INT"));
Database.executeQuery(String.Format(createPortals, givenName));
Database.executeQuery(String.Format(createMessages, givenName));
Database.executeQuery(String.Format(createZones, givenName));
}
public static Level Load(string givenName) { public static Level Load(string givenName) {
return Load(givenName, 0); return Load(givenName, 0);
} }
@ -709,23 +587,7 @@ Owner VARCHAR(20))";
Level level = LvlFile.Load(givenName, path); Level level = LvlFile.Load(givenName, path);
level.setPhysics(phys); level.setPhysics(phys);
level.backedup = true; level.backedup = true;
LoadZones(level, givenName);
using (DataTable ZoneDB = Database.fillData("SELECT * FROM `Zone" + givenName + "`"))
{
Zone Zn;
for (int i = 0; i < ZoneDB.Rows.Count; ++i)
{
DataRow row = ZoneDB.Rows[i];
Zn.smallX = ushort.Parse(row["SmallX"].ToString());
Zn.smallY = ushort.Parse(row["SmallY"].ToString());
Zn.smallZ = ushort.Parse(row["SmallZ"].ToString());
Zn.bigX = ushort.Parse(row["BigX"].ToString());
Zn.bigY = ushort.Parse(row["BigY"].ToString());
Zn.bigZ = ushort.Parse(row["BigZ"].ToString());
Zn.Owner = row["Owner"].ToString();
level.ZoneList.Add(Zn);
}
}
level.jailx = (ushort)(level.spawnx * 32); level.jailx = (ushort)(level.spawnx * 32);
level.jaily = (ushort)(level.spawny * 32); level.jaily = (ushort)(level.spawny * 32);
@ -734,41 +596,8 @@ Owner VARCHAR(20))";
level.jailroty = level.roty; level.jailroty = level.roty;
level.StartPhysics(); level.StartPhysics();
try try {
{ LoadMetadata(level, givenName);
DataTable foundDB = Database.fillData("SELECT * FROM `Portals" + givenName + "`");
for (int i = 0; i < foundDB.Rows.Count; ++i)
{
DataRow row = foundDB.Rows[i];
if (
!Block.portal(level.GetTile(ushort.Parse(row["EntryX"].ToString()),
ushort.Parse(row["EntryY"].ToString()),
ushort.Parse(row["EntryZ"].ToString()))))
{
Database.executeQuery("DELETE FROM `Portals" + givenName + "` WHERE EntryX=" +
row["EntryX"] + " AND EntryY=" +
row["EntryY"] + " AND EntryZ=" +
row["EntryZ"]);
}
}
foundDB = Database.fillData("SELECT * FROM `Messages" + givenName + "`");
for (int i = 0; i < foundDB.Rows.Count; ++i)
{
DataRow row = foundDB.Rows[i];
if (
!Block.mb(level.GetTile(ushort.Parse(row["X"].ToString()),
ushort.Parse(row["Y"].ToString()),
ushort.Parse(row["Z"].ToString()))))
{
//givenName is safe against SQL injections, it gets checked in CmdLoad.cs
Database.executeQuery("DELETE FROM `Messages" + givenName + "` WHERE X=" +
row["X"] + " AND Y=" + row["Y"] +
" AND Z=" + row["Z"]);
}
}
foundDB.Dispose();
} catch (Exception e) { } catch (Exception e) {
Server.ErrorLog(e); Server.ErrorLog(e);
} }

View File

@ -486,6 +486,7 @@
<Compile Include="Levels\IO\LvlProperties.cs" /> <Compile Include="Levels\IO\LvlProperties.cs" />
<Compile Include="Levels\IO\McfFile.cs" /> <Compile Include="Levels\IO\McfFile.cs" />
<Compile Include="Levels\Level.Blocks.cs" /> <Compile Include="Levels\Level.Blocks.cs" />
<Compile Include="Levels\Level.DB.cs" />
<Compile Include="Levels\Level.Physics.cs" /> <Compile Include="Levels\Level.Physics.cs" />
<Compile Include="Levels\LevelActions.cs" /> <Compile Include="Levels\LevelActions.cs" />
<Compile Include="Levels\LevelEnv.cs" /> <Compile Include="Levels\LevelEnv.cs" />

View File

@ -32,7 +32,7 @@ namespace MCGalaxy {
public static void CreatePackage(object p) { public static void CreatePackage(object p) {
BackupArgs args = (BackupArgs)p; BackupArgs args = (BackupArgs)p;
try { try {
CreatePackage(args); CreatePackageCore(args);
} catch (Exception ex) { } catch (Exception ex) {
Server.ErrorLog(ex); Server.ErrorLog(ex);
Server.s.Log("Error while trying to perform backup."); Server.s.Log("Error while trying to perform backup.");