1
0
Fork 0

BlockZapper: Initial import, can zap blocks but not entities

git-svn-id: http://mc-server.googlecode.com/svn/trunk@1439 0a769ca7-a7f5-676a-18bf-c427514a06d6
This commit is contained in:
madmaxoft@gmail.com 2013-05-01 17:27:17 +00:00
parent d55416a649
commit 8aa6f08959
12 changed files with 1421 additions and 0 deletions

View File

@ -0,0 +1,97 @@
// BlockZapper.cpp
// Implements the main app entrypoint
#include "Globals.h"
#include <fstream>
#include "Regions.h"
#include "Zapper.h"
#ifdef _MSC_VER
// Under MSVC, link to WinSock2 (needed by FastNBT's byteswapping)
#pragma comment(lib, "ws2_32.lib")
#endif
void ShowHelp(const char * a_ProgramFullName)
{
AString ProgramName(a_ProgramFullName);
size_t idx = ProgramName.rfind(cFile::PathSeparator);
if (idx != AString::npos)
{
ProgramName.erase(0, idx + 1);
}
printf("Tool written by _Xoft(o), code is public domain.\n");
printf("Usage:\n");
printf("%s [-w <MCAFolder>]\n", ProgramName.c_str());
printf("Zaps blocks and / or entities in specified regions.\n");
printf("Regions are read from stdin, the format is:\n");
printf(" x1 x2 y1 y2 z1 z2 [B|E|BE]\n");
printf("B or no specifier zaps blocks only\n");
printf("E zaps entities only\n");
printf("BE zaps blocks and entities\n");
printf("MCA files are searched in the <MCAFolder>; if not specified, in the current folder.\n");
}
int main(int argc, char * argv[])
{
new cMCLogger; // Create a new logger, it will assign itself as the main logger instance
AString MCAFolder = ".";
for (int i = 1; i < argc; i++)
{
if (strcmp(argv[i], "-w") == 0)
{
if (i < argc - 1)
{
MCAFolder = argv[i + 1];
}
i++;
}
else if (
(strcmp(argv[i], "help") == 0) ||
(strcmp(argv[i], "-?") == 0) ||
(strcmp(argv[i], "/?") == 0) ||
(strcmp(argv[i], "-h") == 0) ||
(strcmp(argv[i], "--help") == 0)
)
{
ShowHelp(argv[0]);
return 0;
}
}
cRegions Regions;
/*
// DEBUG: Read input from a file instead of stdin:
std::fstream fs("test_in.txt");
Regions.Read(fs);
//*/
Regions.Read(std::cin);
cZapper Zapper(MCAFolder);
Zapper.ZapRegions(Regions.GetAll());
LOGINFO("Done");
return 0;
} ;

View File

@ -0,0 +1,34 @@

Microsoft Visual Studio Solution File, Format Version 10.00
# Visual C++ Express 2008
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BlockZapper", "BlockZapper.vcproj", "{CE317695-CCCC-4B11-B07B-21729A110FC2}"
ProjectSection(ProjectDependencies) = postProject
{EA9D50FD-937A-4EF5-8C37-5F4175AF4FEA} = {EA9D50FD-937A-4EF5-8C37-5F4175AF4FEA}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlib", "..\..\..\mc-server.clean\VC2008\zlib.vcproj", "{EA9D50FD-937A-4EF5-8C37-5F4175AF4FEA}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Release profiled|Win32 = Release profiled|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{CE317695-CCCC-4B11-B07B-21729A110FC2}.Debug|Win32.ActiveCfg = Debug|Win32
{CE317695-CCCC-4B11-B07B-21729A110FC2}.Debug|Win32.Build.0 = Debug|Win32
{CE317695-CCCC-4B11-B07B-21729A110FC2}.Release profiled|Win32.ActiveCfg = Release|Win32
{CE317695-CCCC-4B11-B07B-21729A110FC2}.Release profiled|Win32.Build.0 = Release|Win32
{CE317695-CCCC-4B11-B07B-21729A110FC2}.Release|Win32.ActiveCfg = Release|Win32
{CE317695-CCCC-4B11-B07B-21729A110FC2}.Release|Win32.Build.0 = Release|Win32
{EA9D50FD-937A-4EF5-8C37-5F4175AF4FEA}.Debug|Win32.ActiveCfg = Debug|Win32
{EA9D50FD-937A-4EF5-8C37-5F4175AF4FEA}.Debug|Win32.Build.0 = Debug|Win32
{EA9D50FD-937A-4EF5-8C37-5F4175AF4FEA}.Release profiled|Win32.ActiveCfg = Release profiled|Win32
{EA9D50FD-937A-4EF5-8C37-5F4175AF4FEA}.Release profiled|Win32.Build.0 = Release profiled|Win32
{EA9D50FD-937A-4EF5-8C37-5F4175AF4FEA}.Release|Win32.ActiveCfg = Release|Win32
{EA9D50FD-937A-4EF5-8C37-5F4175AF4FEA}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,19 @@
// BlockZapper.txt
/*
This project implements a simple tool that can "zap" blocks out of an Anvil-stored MineCraft world.
It is usually used by server admins when their servers fail with a bug and store an invalid block in the world.
This tool takes a coord triplet and a radius triplet and replaces all blocks within the (new york-metric) radius of the coords with air.
The triplets pair is given on stdin, and multiple such specifiers are allowed, each on a separate file.
If the specifier line ends with an additional " E", entities within that radius are zapped instead of blocks
If the specifier line ends with an additional " BE", both blocks and entities are zapped.
The tool is aware of extended blocktypes (256 .. 4096).
The source code for this tool is public domain, but note that it depends on a few shared sources in MCServer that may be under other licenses.
*/

View File

@ -0,0 +1,313 @@
<?xml version="1.0" encoding="windows-1250"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="9,00"
Name="BlockZapper"
ProjectGUID="{CE317695-CCCC-4B11-B07B-21729A110FC2}"
RootNamespace="BlockZapper"
Keyword="Win32Proj"
TargetFrameworkVersion="196613"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="../../source;../../zlib-1.2.7"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
UsePrecompiledHeader="2"
PrecompiledHeaderThrough="Globals.h"
WarningLevel="3"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="2"
GenerateDebugInformation="true"
SubSystem="1"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="2"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="2"
EnableIntrinsicFunctions="true"
AdditionalIncludeDirectories="../../source;../../zlib-1.2.7"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
RuntimeLibrary="0"
EnableFunctionLevelLinking="true"
UsePrecompiledHeader="2"
PrecompiledHeaderThrough="Globals.h"
WarningLevel="3"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="1"
GenerateDebugInformation="true"
SubSystem="1"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
<File
RelativePath=".\BlockZapper.cpp"
>
</File>
<File
RelativePath=".\Globals.cpp"
>
<FileConfiguration
Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
/>
</FileConfiguration>
</File>
<File
RelativePath=".\Globals.h"
>
</File>
<File
RelativePath=".\Regions.cpp"
>
</File>
<File
RelativePath=".\Regions.h"
>
</File>
<File
RelativePath=".\Zapper.cpp"
>
</File>
<File
RelativePath=".\Zapper.h"
>
</File>
<Filter
Name="shared"
>
<File
RelativePath="..\..\source\Log.cpp"
>
</File>
<File
RelativePath="..\..\source\Log.h"
>
</File>
<File
RelativePath="..\..\source\MCLogger.cpp"
>
</File>
<File
RelativePath="..\..\source\MCLogger.h"
>
</File>
<File
RelativePath="..\..\source\StringCompression.cpp"
>
</File>
<File
RelativePath="..\..\source\StringCompression.h"
>
</File>
<File
RelativePath="..\..\source\StringUtils.cpp"
>
</File>
<File
RelativePath="..\..\source\StringUtils.h"
>
</File>
<Filter
Name="OSSupport"
>
<File
RelativePath="..\..\source\OSSupport\CriticalSection.cpp"
>
</File>
<File
RelativePath="..\..\source\OSSupport\CriticalSection.h"
>
</File>
<File
RelativePath="..\..\source\OSSupport\File.cpp"
>
</File>
<File
RelativePath="..\..\source\OSSupport\File.h"
>
</File>
<File
RelativePath="..\..\source\OSSupport\IsThread.cpp"
>
</File>
<File
RelativePath="..\..\source\OSSupport\IsThread.h"
>
</File>
<File
RelativePath="..\..\source\OSSupport\MakeDir.cpp"
>
</File>
<File
RelativePath="..\..\source\OSSupport\MakeDir.h"
>
</File>
</Filter>
<Filter
Name="WorldStorage"
>
<File
RelativePath="..\..\source\WorldStorage\FastNBT.cpp"
>
</File>
<File
RelativePath="..\..\source\WorldStorage\FastNBT.h"
>
</File>
</Filter>
</Filter>
</Filter>
<File
RelativePath=".\BlockZapper.txt"
>
</File>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

View File

@ -0,0 +1,185 @@
###################################################
#
# Makefile for BlockZapper
# Creator: xoft
#
###################################################
#
# Info:
# This makefile is gnu-make spacific, other make systems needn't understand it
# This makefile generates include-file dependencies into *.d files in each build and then reuses these dependencies in the following builds
#
# Usage:
# To make a release build, call "make"
# To make a debug build, call "make debug=1"
#
###################################################
#
# Macros
#
CC = /usr/bin/g++
all: BlockZapper
###################################################
# Set the variables used for compiling, based on the build mode requested:
# CC_OPTIONS ... options for the C code compiler
# CXX_OPTIONS ... options for the C++ code compiler
# LNK_OPTIONS ... options for the linker
# LNK_LIBS ... libraries to link in
# -- according to http://stackoverflow.com/questions/6183899/undefined-reference-to-dlopen, libs must come after all sources
# BUILDDIR ... folder where the intermediate object files are built
LNK_LIBS = -lstdc++ -ldl -lz
ifeq ($(debug),1)
################
# debug build - fully traceable by gdb in C++ code, slowest
# Since C code is used only for supporting libraries (zlib, lua), it is still O3-optimized
################
CC_OPTIONS = -s -ggdb -g -D_DEBUG -O3
CXX_OPTIONS = -s -ggdb -g -D_DEBUG
LNK_OPTIONS = -pthread -g -ggdb
BUILDDIR = build/debug/
else
ifeq ($(profile),1)
################
# profile build - a release build with symbols and profiling engine built in
################
CC_OPTIONS = -s -g -ggdb -O3 -pg -DNDEBUG
CXX_OPTIONS = -s -g -ggdb -O3 -pg -DNDEBUG
LNK_OPTIONS = -pthread -ggdb -O3 -pg
BUILDDIR = build/profile/
else
ifeq ($(pedantic),1)
################
# pedantic build - basically a debug build with lots of warnings
################
CC_OPTIONS = -s -g -ggdb -D_DEBUG -Wall -Wextra -pedantic -ansi -Wno-long-long
CXX_OPTIONS = -s -g -ggdb -D_DEBUG -Wall -Wextra -pedantic -ansi -Wno-long-long
LNK_OPTIONS = -pthread -ggdb
BUILDDIR = build/pedantic/
else
################
# release build - fastest run-time, no detailed gdb support
################
CC_OPTIONS = -s -g -O3 -DNDEBUG
CXX_OPTIONS = -s -g -O3 -DNDEBUG
LNK_OPTIONS = -pthread -O3
BUILDDIR = build/release/
endif
endif
endif
################
# 32-bit build override in 64-bit build environments
# - so that BearBin doesn't need to modify his makefile after each makefile change :)
################
ifeq ($(addm32),1)
CC_OPTIONS += -m32
CXX_OPTIONS += -m32
LNK_OPTIONS += -m32
endif
###################################################
# INCLUDE directories
#
INCLUDE = -I.\
-I../../source\
-I../../zlib-1.2.7\
###################################################
# Build BlockZapper
#
SOURCES := $(shell find . '(' -name '*.cpp' -o -name '*.c' ')')
SHAREDSOURCES := \
source/Log.cpp \
source/MCLogger.cpp \
source/Noise.cpp \
source/StringCompression.cpp \
source/StringUtils.cpp \
source/OSSupport/CriticalSection.cpp \
source/OSSupport/File.cpp \
source/OSSupport/IsThread.cpp \
source/OSSupport/MakeDir.cpp \
source/WorldStorage/FastNBT.cpp
SHAREDSOURCES := $(filter-out %minigzip.c,$(SHAREDSOURCES))
OBJECTS := $(patsubst %.c,$(BUILDDIR)%.o,$(SOURCES))
OBJECTS := $(patsubst %.cpp,$(BUILDDIR)%.o,$(OBJECTS))
SHAREDOBJECTS := $(patsubst %.c,$(BUILDDIR)%.o,$(SHAREDSOURCES))
SHAREDOBJECTS := $(patsubst %.cpp,$(BUILDDIR)%.o,$(SHAREDOBJECTS))
-include $(patsubst %.o,%.d,$(OBJECTS))
-include $(patsubst %.o,%.d,$(SHAREDOBJECTS))
BlockZapper : $(OBJECTS) $(SHAREDOBJECTS)
$(CC) $(LNK_OPTIONS) $(OBJECTS) $(SHAREDOBJECTS) $(LNK_LIBS) -o BlockZapper
clean :
rm -rf $(BUILDDIR) BlockZapper
install : MCServer
cp MCServer MCServer
###################################################
# Build the parts of BlockZapper
#
# options used:
# -x c ... compile as C code
# -c ... compile but do not link
# -MM ... generate a list of includes
$(BUILDDIR)%.o: %.c
@mkdir -p $(dir $@)
$(CC) $(CC_OPTIONS) -x c -c $(INCLUDE) $< -o $@
@$(CC) $(CC_OPTIONS) -x c -MM $(INCLUDE) $< > $(patsubst %.o,%.d,$@)
@mv -f $(patsubst %.o,%.d,$@) $(patsubst %.o,%.d,$@).tmp
@sed -e "s|.*:|$(BUILDDIR)$*.o:|" < $(patsubst %.o,%.d,$@).tmp > $(patsubst %.o,%.d,$@)
@sed -e 's/.*://' -e 's/\\$$//' < $(patsubst %.o,%.d,$@).tmp | fmt -1 | sed -e 's/^ *//' -e 's/$$/:/' >> $(patsubst %.o,%.d,$@)
@rm -f $(patsubst %.o,%.d,$@).tmp
$(BUILDDIR)%.o: %.cpp
@mkdir -p $(dir $@)
$(CC) $(CXX_OPTIONS) -c $(INCLUDE) $< -o $@
@$(CC) $(CXX_OPTIONS) -MM $(INCLUDE) $< > $(patsubst %.o,%.d,$@)
@mv -f $(patsubst %.o,%.d,$@) $(patsubst %.o,%.d,$@).tmp
@sed -e "s|.*:|$(BUILDDIR)$*.o:|" < $(patsubst %.o,%.d,$@).tmp > $(patsubst %.o,%.d,$@)
@sed -e 's/.*://' -e 's/\\$$//' < $(patsubst %.o,%.d,$@).tmp | fmt -1 | sed -e 's/^ *//' -e 's/$$/:/' >> $(patsubst %.o,%.d,$@)
@rm -f $(patsubst %.o,%.d,$@).tmp
$(BUILDDIR)source/%.o: ../../source/%.cpp
@mkdir -p $(dir $@)
$(CC) $(CXX_OPTIONS) -c $(INCLUDE) $< -o $@
@$(CC) $(CXX_OPTIONS) -MM $(INCLUDE) $< > $(patsubst %.o,%.d,$@)
@mv -f $(patsubst %.o,%.d,$@) $(patsubst %.o,%.d,$@).tmp
@sed -e "s|.*:|$(BUILDDIR)$*.o:|" < $(patsubst %.o,%.d,$@).tmp > $(patsubst %.o,%.d,$@)
@sed -e 's/.*://' -e 's/\\$$//' < $(patsubst %.o,%.d,$@).tmp | fmt -1 | sed -e 's/^ *//' -e 's/$$/:/' >> $(patsubst %.o,%.d,$@)
@rm -f $(patsubst %.o,%.d,$@).tmp

View File

@ -0,0 +1,10 @@
// Globals.cpp
// Used for precompiled header generation in MSVC
#include "Globals.h"

View File

@ -0,0 +1,14 @@
// Globals.h
// This file is used for precompiled header generation in MSVC
#include "../../source/Globals.h"

View File

@ -0,0 +1,167 @@
// Regions.cpp
// Implements the cRegions class representing the list of regions to zap
#include "Globals.h"
#include "Regions.h"
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cRegion:
cRegion::cRegion(void) :
m_MinX(0),
m_MaxX(0),
m_MinY(0),
m_MaxY(0),
m_MinZ(0),
m_MaxZ(0),
m_ShouldZapBlocks(false),
m_ShouldZapEntities(false)
{
}
cRegion::cRegion(int a_MinX, int a_MaxX, int a_MinY, int a_MaxY, int a_MinZ, int a_MaxZ, bool a_ShouldZapBlocks, bool a_ShouldZapEntities) :
m_MinX(a_MinX),
m_MaxX(a_MaxX),
m_MinY(std::max(0, std::min(255, a_MinY))),
m_MaxY(std::max(0, std::min(255, a_MaxY))),
m_MinZ(a_MinZ),
m_MaxZ(a_MaxZ),
m_ShouldZapBlocks(a_ShouldZapBlocks),
m_ShouldZapEntities(a_ShouldZapEntities)
{
}
bool cRegion::TouchesChunk(int a_ChunkX, int a_ChunkZ) const
{
int ChunkBeginX = a_ChunkX * 16;
int ChunkEndX = a_ChunkX * 16 + 15;
int ChunkBeginZ = a_ChunkZ * 16;
int ChunkEndZ = a_ChunkZ * 16 + 15;
if (
(m_MinX > ChunkEndX) || (m_MaxX < ChunkBeginX) ||
(m_MinZ > ChunkEndZ) || (m_MaxZ < ChunkBeginZ)
)
{
return false;
}
return true;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cRegions:
void cRegions::Read(std::istream & a_Stream)
{
while (!a_Stream.eof())
{
AString Line;
std::getline(a_Stream, Line);
// Process the line
AStringVector Split = StringSplit(Line, " \t");
AStringVector NonEmpty;
for (AStringVector::const_iterator itr = Split.begin(), end = Split.end(); itr != end; ++itr)
{
if (!itr->empty())
{
NonEmpty.push_back(*itr);
}
} // for itr - Split[]
switch (NonEmpty.size())
{
case 6:
case 7:
{
AddRegion(NonEmpty);
break;
}
default:
{
fprintf(stderr, "Cannot parse line \"%s\", ignoring", Line.c_str());
break;
}
}
}
}
void cRegions::AddRegion(const AStringVector & a_Split)
{
ASSERT((a_Split.size() == 6) || (a_Split.size() == 7));
int Coords[6];
for (int i = 0; i < 6; i++)
{
Coords[i] = atoi(a_Split[i].c_str());
if ((Coords[i] == 0) && (a_Split[i] != "0"))
{
fprintf(stderr, "Bad coord: \"%s\". Ignoring line.", a_Split[i].c_str());
return;
}
} // for i - a_Split[]
bool ShouldZapBlocks = true;
bool ShouldZapEntities = false;
if (a_Split.size() == 7)
{
AString Upper = a_Split[6];
StrToUpper(Upper);
if (Upper == "E")
{
ShouldZapEntities = true;
ShouldZapBlocks = false;
}
else if (Upper == "BE")
{
ShouldZapEntities = true;
}
else if (Upper == "B")
{
// Nothing needed
}
else
{
fprintf(stderr, "Bad zap specifier: \"%s\". Ignoring line.", a_Split[6].c_str());
return;
}
}
// Swap coords, if needed:
for (int i = 0; i < 3; i++)
{
if (Coords[2 * i] > Coords[2 * i + 1])
{
std::swap(Coords[2 * i], Coords[2 * i + 1]);
}
}
// Store the region
m_Regions.push_back(cRegion(Coords[0], Coords[1], Coords[2], Coords[3], Coords[4], Coords[5], ShouldZapBlocks, ShouldZapEntities));
}

View File

@ -0,0 +1,58 @@
// Regions.h
// Declares the cRegions class representing individual regions to zap
#pragma once
#include <iostream>
struct cRegion
{
int m_MinX, m_MaxX;
int m_MinY, m_MaxY;
int m_MinZ, m_MaxZ;
bool m_ShouldZapBlocks;
bool m_ShouldZapEntities;
cRegion(void);
cRegion(int a_MinX, int a_MaxX, int a_MinY, int a_MaxY, int a_MinZ, int a_MaxZ, bool a_ShouldZapBlocks, bool a_ShouldZapEntities);
bool TouchesChunk(int a_ChunkX, int a_ChunkZ) const;
} ;
typedef std::vector<cRegion> cRegionVector;
class cRegions
{
public:
/// Reads the list of regions from the specified stream
void Read(std::istream & a_Stream);
/// Returns all regions in this container
const cRegionVector & GetAll(void) const { return m_Regions; }
protected:
cRegionVector m_Regions;
/// Adds a new region based on the contents of the split line. The split must already be the correct size
void AddRegion(const AStringVector & a_Split);
} ;

View File

@ -0,0 +1,440 @@
// Zapper.cpp
// Implements the cZapper class representing the processor that actually zaps blocks and entities
#include "Globals.h"
#include "WorldStorage/FastNBT.h"
#include "StringCompression.h"
#include "zlib.h"
#include "Zapper.h"
/// The maximum size of an inflated chunk; raw chunk data is 192 KiB, allow 64 KiB more of entities
#define CHUNK_INFLATE_MAX 256 KiB
cZapper::cZapper(const AString & a_MCAFolder) :
m_MCAFolder(a_MCAFolder)
{
}
void cZapper::ZapRegions(const cRegionVector & a_Regions)
{
for (cRegionVector::const_iterator itr = a_Regions.begin(), end = a_Regions.end(); itr != end; ++itr)
{
int MinAnvX, MinAnvZ;
int MaxAnvX, MaxAnvZ;
BlockToMCA(itr->m_MinX, itr->m_MinZ, MinAnvX, MinAnvZ);
BlockToMCA(itr->m_MaxX, itr->m_MaxZ, MaxAnvX, MaxAnvZ);
for (int x = MinAnvX; x <= MaxAnvX; x++)
{
for (int z = MinAnvZ; z <= MaxAnvZ; z++)
{
ZapRegionInMCAFile(*itr, x, z);
}
}
} // for itr - a_Regions
}
void cZapper::BlockToMCA(int a_BlockX, int a_BlockZ, int & a_MCAX, int & a_MCAZ)
{
// These need to be arithmetic shifts, consult your compiler documentation to see if it's so
// MSVC and GCC both use arithmetic shifts
a_MCAX = a_BlockX >> 10;
a_MCAZ = a_BlockZ >> 10;
}
void cZapper::BlockToChunk(int a_BlockX, int a_BlockZ, int & a_ChunkX, int & a_ChunkZ)
{
// These need to be arithmetic shifts, consult your compiler documentation to see if it's so
// MSVC and GCC both use arithmetic shifts
a_ChunkX = a_BlockX >> 4;
a_ChunkZ = a_BlockZ >> 4;
}
void cZapper::ZapRegionInMCAFile(const cRegion & a_Region, int a_MCAX, int a_MCAZ)
{
cFile fIn;
AString FileNameIn = Printf("%s/r.%d.%d.mca", m_MCAFolder.c_str(), a_MCAX, a_MCAZ);
if (!fIn.Open(FileNameIn, cFile::fmRead))
{
return;
}
cFile fOut;
AString FileNameOut = Printf("%s/r.%d.%d.zap", m_MCAFolder.c_str(), a_MCAX, a_MCAZ);
if (!fOut.Open(FileNameOut, cFile::fmWrite))
{
fprintf(stderr, "Cannot open temporary file \"%s\" for writing, skipping file \"%s\".", FileNameOut.c_str(), FileNameIn.c_str());
return;
}
AString DataOut;
DataOut.reserve(fIn.GetSize());
int HeaderIn[2048];
if (fIn.Read(HeaderIn, sizeof(HeaderIn)) != sizeof(HeaderIn))
{
fprintf(stderr, "Cannot read header from file \"%s\", skipping file.", FileNameIn.c_str());
}
int HeaderOut[2048];
for (int i = 0; i < 1024; i++)
{
if (HeaderIn[i] == 0)
{
// Chunk not present
HeaderOut[i] = 0;
continue;
}
AString ChunkData;
int ChunkX = a_MCAX * ChunksPerMCAX + (i % ChunksPerMCAX);
int ChunkZ = a_MCAZ * ChunksPerMCAZ + (i / ChunksPerMCAX);
LoadChunkData(fIn, HeaderIn[i], ChunkData, ChunkX, ChunkZ);
if (a_Region.TouchesChunk(ChunkX, ChunkZ))
{
ZapRegionInRawChunkData(a_Region, ChunkData, ChunkX, ChunkZ);
}
unsigned char ChunkHeader[5];
size_t DataSize = ChunkData.size() + 1;
ChunkHeader[0] = (DataSize >> 24) & 0xff;
ChunkHeader[1] = (DataSize >> 16) & 0xff;
ChunkHeader[2] = (DataSize >> 8) & 0xff;
ChunkHeader[3] = DataSize & 0xff;
ChunkHeader[4] = 2; // zlib compression
size_t Alignment = 4096 - (ChunkData.size() + 5) % 4096; // 5 bytes of the header are appended outside of ChunkData
if (Alignment > 0)
{
ChunkData.append(Alignment, (char)0);
}
HeaderOut[i] = htonl(((DataOut.size() / 4096 + 2) << 8) | ((ChunkData.size() + 5) / 4096));
DataOut.append((const char *)ChunkHeader, sizeof(ChunkHeader));
DataOut.append(ChunkData);
} // for i - chunks in fIn
for (int i = 1024; i < 2048; i++)
{
HeaderOut[i] = HeaderIn[i];
}
fIn.Close();
fOut.Write(HeaderOut, sizeof(HeaderOut));
fOut.Write(DataOut.data(), DataOut.size());
fOut.Close();
cFile::Delete(FileNameIn);
cFile::Rename(FileNameOut, FileNameIn);
}
void cZapper::LoadChunkData(cFile & a_InFile, int a_ChunkHeaderValue, AString & a_ChunkData, int a_ChunkX, int a_ChunkZ)
{
a_ChunkHeaderValue = ntohl(a_ChunkHeaderValue); // Convert from big-endian to system-endian
int ChunkOffset = (a_ChunkHeaderValue >> 8) * 4096;
int ChunkSize = (a_ChunkHeaderValue & 0xff) * 4096;
a_InFile.Seek(ChunkOffset);
unsigned char ChunkHeader[5];
a_InFile.Read(ChunkHeader, sizeof(ChunkHeader));
if (ChunkHeader[4] != 2)
{
fprintf(stderr, "Chunk [%d, %d] is compressed in an unknown scheme (%d), skipping", a_ChunkX, a_ChunkZ, ChunkHeader[5]);
return;
}
int ActualSize = (ChunkHeader[0] << 24) | (ChunkHeader[1] << 16) | (ChunkHeader[2] << 8) | ChunkHeader[3];
ActualSize -= 1; // Compression took 1 byte
a_ChunkData.resize(ActualSize);
int BytesRead = a_InFile.Read((void *)(a_ChunkData.data()), ActualSize);
if (BytesRead != ActualSize)
{
fprintf(stderr, "Chunk is truncated in file (%d bytes out of %d), skipping.", BytesRead, ActualSize);
a_ChunkData.clear();
return;
}
}
void cZapper::ZapRegionInRawChunkData(const cRegion & a_Region, AString & a_ChunkData, int a_ChunkX, int a_ChunkZ)
{
// Decompress the data:
char Uncompressed[CHUNK_INFLATE_MAX];
z_stream strm;
strm.zalloc = (alloc_func)NULL;
strm.zfree = (free_func)NULL;
strm.opaque = NULL;
inflateInit(&strm);
strm.next_out = (Bytef *)Uncompressed;
strm.avail_out = sizeof(Uncompressed);
strm.next_in = (Bytef *)a_ChunkData.data();
strm.avail_in = a_ChunkData.size();
int res = inflate(&strm, Z_FINISH);
inflateEnd(&strm);
if (res != Z_STREAM_END)
{
fprintf(stderr, "Chunk [%d, %d] failed to decompress: error %d. Skipping chunk.", a_ChunkX, a_ChunkZ, res);
return;
}
/*
// DEBUG: Output src to a file:
cFile f1;
if (f1.Open(Printf("chunk_%d_%d_in.nbt", a_ChunkX, a_ChunkZ), cFile::fmWrite))
{
f1.Write(Uncompressed, strm.total_out);
}
//*/
cParsedNBT NBT(Uncompressed, strm.total_out);
if (!NBT.IsValid())
{
fprintf(stderr, "Chunk [%d, %d] failed to parse. Skipping chunk.", a_ChunkX, a_ChunkZ);
return;
}
ZapRegionInNBTChunk(a_Region, NBT, a_ChunkX, a_ChunkZ);
cFastNBTWriter Writer;
for (int ch = NBT.GetFirstChild(0); ch >= 0; ch = NBT.GetNextSibling(ch))
{
SerializeNBTTag(NBT, ch, Writer);
}
Writer.Finish();
/*
// DEBUG: Output dst to a file:
cFile f2;
if (f2.Open(Printf("chunk_%d_%d_out.nbt", a_ChunkX, a_ChunkZ), cFile::fmWrite))
{
f2.Write(Writer.GetResult().data(), Writer.GetResult().size());
}
//*/
// Compress the serialized data into "Uncompressed" (reuse buffer)
CompressString(Writer.GetResult().data(), Writer.GetResult().size(), a_ChunkData);
}
void cZapper::ZapRegionInNBTChunk(const cRegion & a_Region, cParsedNBT & a_NBT, int a_ChunkX, int a_ChunkZ)
{
int LevelTag = a_NBT.FindChildByName(a_NBT.GetRoot(), "Level");
if (LevelTag < 0)
{
fprintf(stderr, "Cannot find Level tag in chunk [%d, %d]'s NBT. Skipping chunk.", a_ChunkX, a_ChunkZ);
return;
}
// Create a copy of the region and limit it to the current chunk:
int BlockX = a_ChunkX * 16;
int BlockZ = a_ChunkZ * 16;
cRegion Local;
Local.m_MinX = std::max(0, a_Region.m_MinX - BlockX);
Local.m_MaxX = std::min(15, a_Region.m_MaxX - BlockX);
Local.m_MinY = a_Region.m_MinY;
Local.m_MaxY = a_Region.m_MaxY;
Local.m_MinZ = std::max(0, a_Region.m_MinZ - BlockZ);
Local.m_MaxZ = std::min(15, a_Region.m_MaxZ - BlockZ);
if (a_Region.m_ShouldZapBlocks)
{
int SectionsTag = a_NBT.FindChildByName(LevelTag, "Sections");
if (SectionsTag < 0)
{
fprintf(stderr, "Cannot find the Sections tag in the Level tag in chunk [%d, %d]'s NBT. Skipping block-zapping in chunk.", a_ChunkX, a_ChunkZ);
return;
}
ZapRegionBlocksInNBT(Local, a_NBT, SectionsTag);
}
if (a_Region.m_ShouldZapEntities)
{
int EntitiesTag = a_NBT.FindChildByName(LevelTag, "Entities");
if (EntitiesTag < 0)
{
fprintf(stderr, "Cannot find the Entities tag in the Level tag in chunk [%d, %d]'s NBT. Skipping entity-zapping in chunk.", a_ChunkX, a_ChunkZ);
return;
}
ZapRegionEntitiesInNBT(Local, a_NBT, EntitiesTag);
}
}
void cZapper::ZapRegionBlocksInNBT(const cRegion & a_Region, cParsedNBT & a_NBT, int a_SectionsTag)
{
for (int Child = a_NBT.GetFirstChild(a_SectionsTag); Child >= 0; Child = a_NBT.GetNextSibling(Child))
{
int y = 0;
int SectionY = a_NBT.FindChildByName(Child, "Y");
if ((SectionY < 0) || (a_NBT.GetType(SectionY) != TAG_Byte))
{
continue;
}
y = a_NBT.GetByte(SectionY);
if ((y * 16 > a_Region.m_MaxY) || (y * 16 + 16 < a_Region.m_MinY))
{
continue;
}
int BlockDataTag = a_NBT.FindChildByName(Child, "Blocks");
int BlockMetaTag = a_NBT.FindChildByName(Child, "Data");
int BlockAddTag = a_NBT.FindChildByName(Child, "Add");
if (BlockDataTag > 0)
{
ZapRegionInNBTSectionBytes(a_Region, y, (unsigned char *)(a_NBT.GetData(BlockDataTag)));
}
if (BlockMetaTag > 0)
{
ZapRegionInNBTSectionNibbles(a_Region, y, (unsigned char *)(a_NBT.GetData(BlockMetaTag)));
}
if (BlockAddTag > 0)
{
ZapRegionInNBTSectionNibbles(a_Region, y, (unsigned char *)(a_NBT.GetData(BlockAddTag)));
}
} // for Child - Level/Sections/[]
}
void cZapper::ZapRegionInNBTSectionBytes(const cRegion & a_Region, int a_SectionY, unsigned char * a_BlockBytes)
{
int MinY = std::max(0, a_Region.m_MinY - a_SectionY * 16);
int MaxY = std::min(15, a_Region.m_MaxY - a_SectionY * 16);
ASSERT(MinY >= 0);
ASSERT(MaxY >= 0);
for (int y = MinY; y <= MaxY; y++)
{
for (int z = a_Region.m_MinZ; z <= a_Region.m_MaxZ; z++)
{
for (int x = a_Region.m_MinX; x <= a_Region.m_MaxX; x++)
{
a_BlockBytes[x + z * 16 + y * 16 * 16] = 0;
}
}
}
}
void cZapper::ZapRegionInNBTSectionNibbles(const cRegion & a_Region, int a_SectionY, unsigned char * a_BlockNibbles)
{
int MinY = std::max(0, a_Region.m_MinY - a_SectionY * 16);
int MaxY = std::min(15, a_Region.m_MaxY - a_SectionY * 16);
ASSERT(MinY >= 0);
ASSERT(MaxY >= 0);
for (int y = MinY; y <= MaxY; y++)
{
for (int z = a_Region.m_MinZ; z < a_Region.m_MaxZ; z++)
{
for (int x = a_Region.m_MinX; x < a_Region.m_MaxX; x++)
{
cChunkDef::SetNibble(a_BlockNibbles, x, y, z, 0);
}
}
}
}
void cZapper::ZapRegionEntitiesInNBT(const cRegion & a_Region, cParsedNBT & a_NBT, int a_EntitiesTag)
{
// TODO
}
void cZapper::SerializeNBTTag(const cParsedNBT & a_NBT, int a_Tag, cFastNBTWriter & a_Writer)
{
switch (a_NBT.GetType(a_Tag))
{
case TAG_Byte: a_Writer.AddByte (a_NBT.GetName(a_Tag), a_NBT.GetByte (a_Tag)); break;
case TAG_Short: a_Writer.AddShort (a_NBT.GetName(a_Tag), a_NBT.GetShort (a_Tag)); break;
case TAG_Int: a_Writer.AddInt (a_NBT.GetName(a_Tag), a_NBT.GetInt (a_Tag)); break;
case TAG_Long: a_Writer.AddLong (a_NBT.GetName(a_Tag), a_NBT.GetLong (a_Tag)); break;
case TAG_Float: a_Writer.AddFloat (a_NBT.GetName(a_Tag), a_NBT.GetFloat (a_Tag)); break;
case TAG_Double: a_Writer.AddDouble (a_NBT.GetName(a_Tag), a_NBT.GetDouble(a_Tag)); break;
case TAG_ByteArray: a_Writer.AddByteArray(a_NBT.GetName(a_Tag), a_NBT.GetData (a_Tag), a_NBT.GetDataLength(a_Tag)); break;
case TAG_String: a_Writer.AddString (a_NBT.GetName(a_Tag), a_NBT.GetString(a_Tag)); break;
case TAG_IntArray:
{
std::vector<int> Data;
int NumInts = a_NBT.GetDataLength(a_Tag) / 4;
Data.reserve(NumInts);
int * OrigData = (int *)(a_NBT.GetData(a_Tag));
for (int i = 0; i < NumInts; i++)
{
Data.push_back(ntohl(OrigData[i]));
}
a_Writer.AddIntArray (a_NBT.GetName(a_Tag), &Data.front(), Data.size()); break;
}
case TAG_List:
{
a_Writer.BeginList(a_NBT.GetName(a_Tag), a_NBT.GetChildrenType(a_Tag));
for (int ch = a_NBT.GetFirstChild(a_Tag); ch >= 0; ch = a_NBT.GetNextSibling(ch))
{
SerializeNBTTag(a_NBT, ch, a_Writer);
} // for ch - children[]
a_Writer.EndList();
break;
}
case TAG_Compound:
{
a_Writer.BeginCompound(a_NBT.GetName(a_Tag));
for (int ch = a_NBT.GetFirstChild(a_Tag); ch >= 0; ch = a_NBT.GetNextSibling(ch))
{
SerializeNBTTag(a_NBT, ch, a_Writer);
} // for ch - children[]
a_Writer.EndCompound();
break;
}
default:
{
ASSERT(!"Unknown NBT tag");
break;
}
}
}

View File

@ -0,0 +1,80 @@
// Zapper.h
// Declares the cZapper class representing the processor that actually zaps blocks and entities
#pragma once
#include "Regions.h"
// fwd: ParsedNBT.h
class cParsedNBT;
class cFastNBTWriter;
class cZapper
{
public:
cZapper(const AString & a_MCAFolder);
/// Zaps all the specified regions
void ZapRegions(const cRegionVector & a_Regions);
protected:
static const int BlocksPerChunkX = 16;
static const int BlocksPerChunkZ = 16;
static const int ChunksPerMCAX = 32;
static const int ChunksPerMCAZ = 32;
AString m_MCAFolder;
/// Converts from block coords to MCA coords
void BlockToMCA(int a_BlockX, int a_BlockZ, int & a_MCAX, int & a_MCAZ);
/// Converts from block coords to chunk coords
void BlockToChunk(int a_BlockX, int a_BlockZ, int & a_ChunkX, int & a_ChunkZ);
/// Zaps the specified region in the MCA file with the specified MCA coords
void ZapRegionInMCAFile(const cRegion & a_Region, int a_MCAX, int a_MCAZ);
/** Loads raw compressed chunk data from the specified file
* chunk is specified by ChunkHeaderValue, which is the int describing the chunk in file header.
*/
void LoadChunkData(cFile & a_InFile, int a_ChunkHeaderValue, AString & a_ChunkData, int a_ChunkX, int a_ChunkZ);
/// Zaps the specified region in the raw (compressed) chunk data.
void ZapRegionInRawChunkData(const cRegion & a_Region, AString & a_ChunkData, int a_ChunkX, int a_ChunkZ);
/// Zaps the specified region in the specified NBT structure
void ZapRegionInNBTChunk(const cRegion & a_Region, cParsedNBT & a_NBT, int a_ChunkX, int a_ChunkZ);
/// Zaps the blocks in the specified region from the specified NBT
void ZapRegionBlocksInNBT(const cRegion & a_Region, cParsedNBT & a_NBT, int a_SectionsTag);
/// Zaps the blocks in the specified bytes (types) from one vertical section (16^3 blocks) of a chunk.
void ZapRegionInNBTSectionBytes(const cRegion & a_Region, int a_SectionY, unsigned char * a_BlockBytes);
/// Zaps the blocks in the specified nibbles (meta, add) from one vertical section (16^3 blocks) of a chunk.
void ZapRegionInNBTSectionNibbles(const cRegion & a_Region, int a_SectionY, unsigned char * a_BlockNibbles);
/// Zaps entities in the specified region from the specified NBT
void ZapRegionEntitiesInNBT(const cRegion & a_Region, cParsedNBT & a_NBT, int a_EntitiesTag);
/// Serializes the NBT subtree into a writer
void SerializeNBTTag(const cParsedNBT & a_NBT, int a_Tag, cFastNBTWriter & a_Writer);
} ;

View File

@ -1744,6 +1744,10 @@
RelativePath="..\source\Generating\ComposableGenerator.h"
>
</File>
<File
RelativePath="..\source\Generating\DistortedHeightmap.h"
>
</File>
<File
RelativePath="..\source\Generating\FinishGen.cpp"
>