From 88f3fe7f000992fe7a3c47d4e235f725e9b77b69 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Fri, 30 Aug 2013 17:29:46 +0200 Subject: [PATCH 1/6] Moved throw pos and speed calculation from cProjectileEntity into cPlayer. --- source/Bindings.cpp | 174 ++++++++++++++------------- source/Bindings.h | 2 +- source/Entities/Player.cpp | 30 +++++ source/Entities/Player.h | 8 +- source/Entities/ProjectileEntity.cpp | 32 +---- source/Entities/ProjectileEntity.h | 6 - 6 files changed, 128 insertions(+), 124 deletions(-) diff --git a/source/Bindings.cpp b/source/Bindings.cpp index af3e83dda..898d3af1b 100644 --- a/source/Bindings.cpp +++ b/source/Bindings.cpp @@ -1,6 +1,6 @@ /* ** Lua binding: AllToLua -** Generated automatically by tolua++-1.0.92 on 08/30/13 14:30:24. +** Generated automatically by tolua++-1.0.92 on 08/30/13 17:24:30. */ #ifndef __cplusplus @@ -7650,6 +7650,92 @@ static int tolua_AllToLua_cPlayer_GetEquippedItem00(lua_State* tolua_S) } #endif //#ifndef TOLUA_DISABLE +/* method: GetThrowStartPos of class cPlayer */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cPlayer_GetThrowStartPos00 +static int tolua_AllToLua_cPlayer_GetThrowStartPos00(lua_State* tolua_S) +{ +#ifndef TOLUA_RELEASE + tolua_Error tolua_err; + if ( + !tolua_isusertype(tolua_S,1,"const cPlayer",0,&tolua_err) || + !tolua_isnoobj(tolua_S,2,&tolua_err) + ) + goto tolua_lerror; + else +#endif + { + const cPlayer* self = (const cPlayer*) tolua_tousertype(tolua_S,1,0); +#ifndef TOLUA_RELEASE + if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetThrowStartPos'", NULL); +#endif + { + Vector3d tolua_ret = (Vector3d) self->GetThrowStartPos(); + { +#ifdef __cplusplus + void* tolua_obj = Mtolua_new((Vector3d)(tolua_ret)); + tolua_pushusertype(tolua_S,tolua_obj,"Vector3d"); + tolua_register_gc(tolua_S,lua_gettop(tolua_S)); +#else + void* tolua_obj = tolua_copy(tolua_S,(void*)&tolua_ret,sizeof(Vector3d)); + tolua_pushusertype(tolua_S,tolua_obj,"Vector3d"); + tolua_register_gc(tolua_S,lua_gettop(tolua_S)); +#endif + } + } + } + return 1; +#ifndef TOLUA_RELEASE + tolua_lerror: + tolua_error(tolua_S,"#ferror in function 'GetThrowStartPos'.",&tolua_err); + return 0; +#endif +} +#endif //#ifndef TOLUA_DISABLE + +/* method: GetThrowSpeed of class cPlayer */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cPlayer_GetThrowSpeed00 +static int tolua_AllToLua_cPlayer_GetThrowSpeed00(lua_State* tolua_S) +{ +#ifndef TOLUA_RELEASE + tolua_Error tolua_err; + if ( + !tolua_isusertype(tolua_S,1,"const cPlayer",0,&tolua_err) || + !tolua_isnumber(tolua_S,2,0,&tolua_err) || + !tolua_isnoobj(tolua_S,3,&tolua_err) + ) + goto tolua_lerror; + else +#endif + { + const cPlayer* self = (const cPlayer*) tolua_tousertype(tolua_S,1,0); + double a_SpeedCoeff = ((double) tolua_tonumber(tolua_S,2,0)); +#ifndef TOLUA_RELEASE + if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetThrowSpeed'", NULL); +#endif + { + Vector3d tolua_ret = (Vector3d) self->GetThrowSpeed(a_SpeedCoeff); + { +#ifdef __cplusplus + void* tolua_obj = Mtolua_new((Vector3d)(tolua_ret)); + tolua_pushusertype(tolua_S,tolua_obj,"Vector3d"); + tolua_register_gc(tolua_S,lua_gettop(tolua_S)); +#else + void* tolua_obj = tolua_copy(tolua_S,(void*)&tolua_ret,sizeof(Vector3d)); + tolua_pushusertype(tolua_S,tolua_obj,"Vector3d"); + tolua_register_gc(tolua_S,lua_gettop(tolua_S)); +#endif + } + } + } + return 1; +#ifndef TOLUA_RELEASE + tolua_lerror: + tolua_error(tolua_S,"#ferror in function 'GetThrowSpeed'.",&tolua_err); + return 0; +#endif +} +#endif //#ifndef TOLUA_DISABLE + /* method: GetGameMode of class cPlayer */ #ifndef TOLUA_DISABLE_tolua_AllToLua_cPlayer_GetGameMode00 static int tolua_AllToLua_cPlayer_GetGameMode00(lua_State* tolua_S) @@ -9704,88 +9790,6 @@ static int tolua_AllToLua_cProjectileEntity_IsInGround00(lua_State* tolua_S) } #endif //#ifndef TOLUA_DISABLE -/* method: PosFromPlayerPos of class cArrowEntity */ -#ifndef TOLUA_DISABLE_tolua_AllToLua_cArrowEntity_PosFromPlayerPos00 -static int tolua_AllToLua_cArrowEntity_PosFromPlayerPos00(lua_State* tolua_S) -{ -#ifndef TOLUA_RELEASE - tolua_Error tolua_err; - if ( - !tolua_isusertable(tolua_S,1,"cArrowEntity",0,&tolua_err) || - (tolua_isvaluenil(tolua_S,2,&tolua_err) || !tolua_isusertype(tolua_S,2,"const cPlayer",0,&tolua_err)) || - !tolua_isnoobj(tolua_S,3,&tolua_err) - ) - goto tolua_lerror; - else -#endif - { - const cPlayer* a_Player = ((const cPlayer*) tolua_tousertype(tolua_S,2,0)); - { - Vector3d tolua_ret = (Vector3d) cArrowEntity::PosFromPlayerPos(*a_Player); - { -#ifdef __cplusplus - void* tolua_obj = Mtolua_new((Vector3d)(tolua_ret)); - tolua_pushusertype(tolua_S,tolua_obj,"Vector3d"); - tolua_register_gc(tolua_S,lua_gettop(tolua_S)); -#else - void* tolua_obj = tolua_copy(tolua_S,(void*)&tolua_ret,sizeof(Vector3d)); - tolua_pushusertype(tolua_S,tolua_obj,"Vector3d"); - tolua_register_gc(tolua_S,lua_gettop(tolua_S)); -#endif - } - } - } - return 1; -#ifndef TOLUA_RELEASE - tolua_lerror: - tolua_error(tolua_S,"#ferror in function 'PosFromPlayerPos'.",&tolua_err); - return 0; -#endif -} -#endif //#ifndef TOLUA_DISABLE - -/* method: SpeedFromPlayerLook of class cArrowEntity */ -#ifndef TOLUA_DISABLE_tolua_AllToLua_cArrowEntity_SpeedFromPlayerLook00 -static int tolua_AllToLua_cArrowEntity_SpeedFromPlayerLook00(lua_State* tolua_S) -{ -#ifndef TOLUA_RELEASE - tolua_Error tolua_err; - if ( - !tolua_isusertable(tolua_S,1,"cArrowEntity",0,&tolua_err) || - (tolua_isvaluenil(tolua_S,2,&tolua_err) || !tolua_isusertype(tolua_S,2,"const cPlayer",0,&tolua_err)) || - !tolua_isnumber(tolua_S,3,0,&tolua_err) || - !tolua_isnoobj(tolua_S,4,&tolua_err) - ) - goto tolua_lerror; - else -#endif - { - const cPlayer* a_Player = ((const cPlayer*) tolua_tousertype(tolua_S,2,0)); - double a_Force = ((double) tolua_tonumber(tolua_S,3,0)); - { - Vector3d tolua_ret = (Vector3d) cArrowEntity::SpeedFromPlayerLook(*a_Player,a_Force); - { -#ifdef __cplusplus - void* tolua_obj = Mtolua_new((Vector3d)(tolua_ret)); - tolua_pushusertype(tolua_S,tolua_obj,"Vector3d"); - tolua_register_gc(tolua_S,lua_gettop(tolua_S)); -#else - void* tolua_obj = tolua_copy(tolua_S,(void*)&tolua_ret,sizeof(Vector3d)); - tolua_pushusertype(tolua_S,tolua_obj,"Vector3d"); - tolua_register_gc(tolua_S,lua_gettop(tolua_S)); -#endif - } - } - } - return 1; -#ifndef TOLUA_RELEASE - tolua_lerror: - tolua_error(tolua_S,"#ferror in function 'SpeedFromPlayerLook'.",&tolua_err); - return 0; -#endif -} -#endif //#ifndef TOLUA_DISABLE - /* method: GetPickupState of class cArrowEntity */ #ifndef TOLUA_DISABLE_tolua_AllToLua_cArrowEntity_GetPickupState00 static int tolua_AllToLua_cArrowEntity_GetPickupState00(lua_State* tolua_S) @@ -28588,6 +28592,8 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S) tolua_function(tolua_S,"GetStance",tolua_AllToLua_cPlayer_GetStance00); tolua_function(tolua_S,"GetInventory",tolua_AllToLua_cPlayer_GetInventory00); tolua_function(tolua_S,"GetEquippedItem",tolua_AllToLua_cPlayer_GetEquippedItem00); + tolua_function(tolua_S,"GetThrowStartPos",tolua_AllToLua_cPlayer_GetThrowStartPos00); + tolua_function(tolua_S,"GetThrowSpeed",tolua_AllToLua_cPlayer_GetThrowSpeed00); tolua_function(tolua_S,"GetGameMode",tolua_AllToLua_cPlayer_GetGameMode00); tolua_function(tolua_S,"SetGameMode",tolua_AllToLua_cPlayer_SetGameMode00); tolua_function(tolua_S,"IsGameModeCreative",tolua_AllToLua_cPlayer_IsGameModeCreative00); @@ -28677,8 +28683,6 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S) tolua_constant(tolua_S,"psNoPickup",cArrowEntity::psNoPickup); tolua_constant(tolua_S,"psInSurvivalOrCreative",cArrowEntity::psInSurvivalOrCreative); tolua_constant(tolua_S,"psInCreative",cArrowEntity::psInCreative); - tolua_function(tolua_S,"PosFromPlayerPos",tolua_AllToLua_cArrowEntity_PosFromPlayerPos00); - tolua_function(tolua_S,"SpeedFromPlayerLook",tolua_AllToLua_cArrowEntity_SpeedFromPlayerLook00); tolua_function(tolua_S,"GetPickupState",tolua_AllToLua_cArrowEntity_GetPickupState00); tolua_function(tolua_S,"SetPickupState",tolua_AllToLua_cArrowEntity_SetPickupState00); tolua_function(tolua_S,"GetDamageCoeff",tolua_AllToLua_cArrowEntity_GetDamageCoeff00); diff --git a/source/Bindings.h b/source/Bindings.h index e5b7e0f76..e4871e9f6 100644 --- a/source/Bindings.h +++ b/source/Bindings.h @@ -1,6 +1,6 @@ /* ** Lua binding: AllToLua -** Generated automatically by tolua++-1.0.92 on 08/30/13 14:30:25. +** Generated automatically by tolua++-1.0.92 on 08/30/13 17:24:30. */ /* Exported function */ diff --git a/source/Entities/Player.cpp b/source/Entities/Player.cpp index 0cb047933..0943f61ff 100644 --- a/source/Entities/Player.cpp +++ b/source/Entities/Player.cpp @@ -857,6 +857,36 @@ void cPlayer::TeleportToCoords(double a_PosX, double a_PosY, double a_PosZ) +Vector3d cPlayer::GetThrowStartPos(void) const +{ + Vector3d res = GetEyePosition(); + + // Adjust the position to be just outside the player's bounding box: + res.x += 0.16 * cos(GetPitch()); + res.y += -0.1; + res.z += 0.16 * sin(GetPitch()); + + return res; +} + + + + + +Vector3d cPlayer::GetThrowSpeed(double a_SpeedCoeff) const +{ + Vector3d res = GetLookVector(); + res.Normalize(); + + // TODO: Add a slight random change (+-0.0075 in each direction) + + return res * a_SpeedCoeff; +} + + + + + void cPlayer::MoveTo( const Vector3d & a_NewPos ) { if ((a_NewPos.y < -990) && (GetPosY() > -100)) diff --git a/source/Entities/Player.h b/source/Entities/Player.h index 4adf946db..82ff48954 100644 --- a/source/Entities/Player.h +++ b/source/Entities/Player.h @@ -73,7 +73,7 @@ public: void CancelChargingBow(void); /// Returns true if the player is currently charging the bow - bool IsChargingBox(void) const { return m_IsChargingBow; } + bool IsChargingBow(void) const { return m_IsChargingBow; } void SetTouchGround( bool a_bTouchGround ); inline void SetStance( const double a_Stance ) { m_Stance = a_Stance; } @@ -90,6 +90,12 @@ public: // tolua_begin + /// Returns the position where projectiles thrown by this player should start, player eye position + adjustment + Vector3d GetThrowStartPos(void) const; + + /// Returns the initial speed vector of a throw, with a 3D length of a_SpeedCoeff. + Vector3d GetThrowSpeed(double a_SpeedCoeff) const; + /// Returns the current gamemode. Partly OBSOLETE, you should use IsGameModeXXX() functions wherever applicable eGameMode GetGameMode(void) const { return m_GameMode; } diff --git a/source/Entities/ProjectileEntity.cpp b/source/Entities/ProjectileEntity.cpp index f405e9aa4..1dbc46ca1 100644 --- a/source/Entities/ProjectileEntity.cpp +++ b/source/Entities/ProjectileEntity.cpp @@ -230,7 +230,7 @@ cArrowEntity::cArrowEntity(cEntity * a_Creator, double a_X, double a_Y, double a cArrowEntity::cArrowEntity(cPlayer & a_Player, double a_Force) : - super(pkArrow, &a_Player, PosFromPlayerPos(a_Player), SpeedFromPlayerLook(a_Player, a_Force), 0.5, 0.5), + super(pkArrow, &a_Player, a_Player.GetThrowStartPos(), a_Player.GetThrowSpeed(a_Force * 1.5 * 20), 0.5, 0.5), m_PickupState(psInSurvivalOrCreative), m_DamageCoeff(2) { @@ -240,36 +240,6 @@ cArrowEntity::cArrowEntity(cPlayer & a_Player, double a_Force) : -Vector3d cArrowEntity::PosFromPlayerPos(const cPlayer & a_Player) -{ - Vector3d res = a_Player.GetEyePosition(); - - // Adjust the position to be just outside the player's bounding box: - res.x += 0.16 * cos(a_Player.GetPitch()); - res.y += -0.1; - res.z += 0.16 * sin(a_Player.GetPitch()); - - return res; -} - - - - - -Vector3d cArrowEntity::SpeedFromPlayerLook(const cPlayer & a_Player, double a_Force) -{ - Vector3d res = a_Player.GetLookVector(); - res.Normalize(); - - // TODO: Add a slight random change (+-0.0075 in each direction) - - return res * a_Force * 1.5 * 20; -} - - - - - bool cArrowEntity::CanPickup(const cPlayer & a_Player) const { switch (m_PickupState) diff --git a/source/Entities/ProjectileEntity.h b/source/Entities/ProjectileEntity.h index 1569ad035..aa7ecc772 100644 --- a/source/Entities/ProjectileEntity.h +++ b/source/Entities/ProjectileEntity.h @@ -112,12 +112,6 @@ public: // tolua_begin - /// Returns the initial arrow position, as defined by the player eye position + adjustment. - static Vector3d PosFromPlayerPos(const cPlayer & a_Player); - - /// Returns the initial arrow speed, as defined by the player look vector and the force coefficient - static Vector3d SpeedFromPlayerLook(const cPlayer & a_Player, double a_Force); - /// Returns whether the arrow can be picked up by players ePickupState GetPickupState(void) const { return m_PickupState; } From d7a52870003e46858bec65cc76880cecc5de7bb8 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Fri, 30 Aug 2013 18:10:58 +0200 Subject: [PATCH 2/6] Basic support for thrown items - eggs, snowballs and ender pearls. They can be thrown, but they don't do anything on impact. Also they don't save to nor load from MCA. --- VC2008/MCServer.vcproj | 4 ++ source/Bindings.cpp | 60 +++++++++++------- source/Bindings.h | 2 +- source/Entities/ProjectileEntity.cpp | 91 ++++++++++++++++++++++++++- source/Entities/ProjectileEntity.h | 93 +++++++++++++++++++++++++++- source/Items/ItemHandler.cpp | 4 ++ source/Items/ItemThrowable.h | 90 +++++++++++++++++++++++++++ 7 files changed, 314 insertions(+), 30 deletions(-) create mode 100644 source/Items/ItemThrowable.h diff --git a/VC2008/MCServer.vcproj b/VC2008/MCServer.vcproj index fb82c3520..7ffa3c887 100644 --- a/VC2008/MCServer.vcproj +++ b/VC2008/MCServer.vcproj @@ -2347,6 +2347,10 @@ RelativePath="..\source\items\ItemSword.h" > + + diff --git a/source/Bindings.cpp b/source/Bindings.cpp index 898d3af1b..cbe728cbf 100644 --- a/source/Bindings.cpp +++ b/source/Bindings.cpp @@ -1,6 +1,6 @@ /* ** Lua binding: AllToLua -** Generated automatically by tolua++-1.0.92 on 08/30/13 17:24:30. +** Generated automatically by tolua++-1.0.92 on 08/30/13 18:03:04. */ #ifndef __cplusplus @@ -203,63 +203,66 @@ static int tolua_collect_Vector3d (lua_State* tolua_S) /* function to register type */ static void tolua_reg_types (lua_State* tolua_S) { + tolua_usertype(tolua_S,"cThrownEnderPearlEntity"); tolua_usertype(tolua_S,"TakeDamageInfo"); - tolua_usertype(tolua_S,"cServer"); + tolua_usertype(tolua_S,"cPluginManager"); + tolua_usertype(tolua_S,"cMonster"); + tolua_usertype(tolua_S,"cCraftingGrid"); tolua_usertype(tolua_S,"cCraftingRecipe"); tolua_usertype(tolua_S,"cPlugin"); - tolua_usertype(tolua_S,"cMonster"); + tolua_usertype(tolua_S,"cWindow"); tolua_usertype(tolua_S,"cStringMap"); tolua_usertype(tolua_S,"cItemGrid"); tolua_usertype(tolua_S,"cBlockArea"); tolua_usertype(tolua_S,"cEnchantments"); tolua_usertype(tolua_S,"cLuaWindow"); - tolua_usertype(tolua_S,"cInventory"); + tolua_usertype(tolua_S,"cServer"); tolua_usertype(tolua_S,"cRoot"); - tolua_usertype(tolua_S,"cWindow"); + tolua_usertype(tolua_S,"cCuboid"); tolua_usertype(tolua_S,"std::vector"); - tolua_usertype(tolua_S,"cCraftingGrid"); + tolua_usertype(tolua_S,"cGroup"); tolua_usertype(tolua_S,"cPickup"); tolua_usertype(tolua_S,"std::vector"); - tolua_usertype(tolua_S,"cGroup"); + tolua_usertype(tolua_S,"cTracer"); tolua_usertype(tolua_S,"cClientHandle"); tolua_usertype(tolua_S,"cChunkDesc"); tolua_usertype(tolua_S,"cFurnaceRecipe"); - tolua_usertype(tolua_S,"cTracer"); - tolua_usertype(tolua_S,"cChatColor"); - tolua_usertype(tolua_S,"cCuboid"); tolua_usertype(tolua_S,"Vector3i"); - tolua_usertype(tolua_S,"cWorld"); - tolua_usertype(tolua_S,"cEntity"); + tolua_usertype(tolua_S,"cChatColor"); + tolua_usertype(tolua_S,"cThrownSnowballEntity"); + tolua_usertype(tolua_S,"cWebAdmin"); tolua_usertype(tolua_S,"cCraftingRecipes"); + tolua_usertype(tolua_S,"cItems"); + tolua_usertype(tolua_S,"cWebPlugin"); tolua_usertype(tolua_S,"cItem"); tolua_usertype(tolua_S,"Vector3f"); tolua_usertype(tolua_S,"cArrowEntity"); tolua_usertype(tolua_S,"cDropSpenserEntity"); - tolua_usertype(tolua_S,"cWebPlugin"); - tolua_usertype(tolua_S,"cWebAdmin"); + tolua_usertype(tolua_S,"sWebAdminPage"); + tolua_usertype(tolua_S,"HTTPFormData"); tolua_usertype(tolua_S,"cChestEntity"); tolua_usertype(tolua_S,"cDispenserEntity"); - tolua_usertype(tolua_S,"sWebAdminPage"); + tolua_usertype(tolua_S,"HTTPRequest"); tolua_usertype(tolua_S,"cBlockEntity"); tolua_usertype(tolua_S,"cItemGrid::cListener"); tolua_usertype(tolua_S,"HTTPTemplateRequest"); - tolua_usertype(tolua_S,"HTTPRequest"); - tolua_usertype(tolua_S,"HTTPFormData"); tolua_usertype(tolua_S,"cFurnaceEntity"); tolua_usertype(tolua_S,"cDropperEntity"); - tolua_usertype(tolua_S,"cLineBlockTracer"); - tolua_usertype(tolua_S,"cPluginManager"); - tolua_usertype(tolua_S,"cIniFile"); + tolua_usertype(tolua_S,"cPluginLua"); tolua_usertype(tolua_S,"cBlockEntityWithItems"); + tolua_usertype(tolua_S,"cLineBlockTracer"); + tolua_usertype(tolua_S,"cCriticalSection"); + tolua_usertype(tolua_S,"cIniFile"); + tolua_usertype(tolua_S,"cEntity"); tolua_usertype(tolua_S,"cListeners"); tolua_usertype(tolua_S,"cPawn"); - tolua_usertype(tolua_S,"cPlayer"); + tolua_usertype(tolua_S,"cThrownEggEntity"); tolua_usertype(tolua_S,"cGroupManager"); tolua_usertype(tolua_S,"cBlockEntityWindowOwner"); - tolua_usertype(tolua_S,"cCriticalSection"); + tolua_usertype(tolua_S,"cInventory"); tolua_usertype(tolua_S,"cProjectileEntity"); - tolua_usertype(tolua_S,"cPluginLua"); - tolua_usertype(tolua_S,"cItems"); + tolua_usertype(tolua_S,"cWorld"); + tolua_usertype(tolua_S,"cPlayer"); tolua_usertype(tolua_S,"Vector3d"); } @@ -28689,6 +28692,15 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S) tolua_function(tolua_S,"SetDamageCoeff",tolua_AllToLua_cArrowEntity_SetDamageCoeff00); tolua_function(tolua_S,"CanPickup",tolua_AllToLua_cArrowEntity_CanPickup00); tolua_endmodule(tolua_S); + tolua_cclass(tolua_S,"cThrownEggEntity","cThrownEggEntity","cProjectileEntity",NULL); + tolua_beginmodule(tolua_S,"cThrownEggEntity"); + tolua_endmodule(tolua_S); + tolua_cclass(tolua_S,"cThrownEnderPearlEntity","cThrownEnderPearlEntity","cProjectileEntity",NULL); + tolua_beginmodule(tolua_S,"cThrownEnderPearlEntity"); + tolua_endmodule(tolua_S); + tolua_cclass(tolua_S,"cThrownSnowballEntity","cThrownSnowballEntity","cProjectileEntity",NULL); + tolua_beginmodule(tolua_S,"cThrownSnowballEntity"); + tolua_endmodule(tolua_S); tolua_cclass(tolua_S,"cPluginManager","cPluginManager","",NULL); tolua_beginmodule(tolua_S,"cPluginManager"); tolua_constant(tolua_S,"HOOK_BLOCK_TO_PICKUPS",cPluginManager::HOOK_BLOCK_TO_PICKUPS); diff --git a/source/Bindings.h b/source/Bindings.h index e4871e9f6..faa81e4c8 100644 --- a/source/Bindings.h +++ b/source/Bindings.h @@ -1,6 +1,6 @@ /* ** Lua binding: AllToLua -** Generated automatically by tolua++-1.0.92 on 08/30/13 17:24:30. +** Generated automatically by tolua++-1.0.92 on 08/30/13 18:03:05. */ /* Exported function */ diff --git a/source/Entities/ProjectileEntity.cpp b/source/Entities/ProjectileEntity.cpp index 1dbc46ca1..91b2c97a8 100644 --- a/source/Entities/ProjectileEntity.cpp +++ b/source/Entities/ProjectileEntity.cpp @@ -101,11 +101,14 @@ cProjectileEntity * cProjectileEntity::Create(eKind a_Kind, cEntity * a_Creator, switch (a_Kind) { - case pkArrow: return new cArrowEntity(a_Creator, a_X, a_Y, a_Z, Speed); + case pkArrow: return new cArrowEntity (a_Creator, a_X, a_Y, a_Z, Speed); + case pkEgg: return new cThrownEggEntity (a_Creator, a_X, a_Y, a_Z, Speed); + case pkEnderPearl: return new cThrownEnderPearlEntity(a_Creator, a_X, a_Y, a_Z, Speed); + case pkSnowball: return new cThrownSnowballEntity (a_Creator, a_X, a_Y, a_Z, Speed); // TODO: the rest } - LOGWARNING("%s: Unknown kind: %d", __FUNCTION__, a_Kind); + LOGWARNING("%s: Unknown projectile kind: %d", __FUNCTION__, a_Kind); return NULL; } @@ -210,10 +213,20 @@ void cProjectileEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk) +void cProjectileEntity::SpawnOn(cClientHandle & a_Client) +{ + // Default spawning - use the projectile kind to spawn an object: + a_Client.SendSpawnObject(*this, m_ProjectileKind, 0, 0, 0); +} + + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // cArrowEntity: -cArrowEntity::cArrowEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d a_Speed) : +cArrowEntity::cArrowEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) : super(pkArrow, a_Creator, a_X, a_Y, a_Z, 0.5, 0.5), m_PickupState(psNoPickup), m_DamageCoeff(2) @@ -264,3 +277,75 @@ void cArrowEntity::SpawnOn(cClientHandle & a_Client) +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cThrownEggEntity: + +cThrownEggEntity::cThrownEggEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) : + super(pkEgg, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25) +{ + SetSpeed(a_Speed); +} + + + + + +void cThrownEggEntity::OnHitSolidBlock(int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace) +{ + // TODO: Random-spawn a chicken or four + + Destroy(); +} + + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cThrownEnderPearlEntity : + +cThrownEnderPearlEntity::cThrownEnderPearlEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) : + super(pkEnderPearl, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25) +{ + SetSpeed(a_Speed); +} + + + + + +void cThrownEnderPearlEntity::OnHitSolidBlock(int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace) +{ + // TODO: Teleport the creator here, make them take 5 damage + + Destroy(); +} + + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cThrownSnowballEntity : + +cThrownSnowballEntity::cThrownSnowballEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) : + super(pkSnowball, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25) +{ + SetSpeed(a_Speed); +} + + + + + +void cThrownSnowballEntity::OnHitSolidBlock(int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace) +{ + // TODO: Apply damage to certain mobs (blaze etc.) and anger all mobs + + Destroy(); +} + + + + + diff --git a/source/Entities/ProjectileEntity.h b/source/Entities/ProjectileEntity.h index aa7ecc772..95dc00abc 100644 --- a/source/Entities/ProjectileEntity.h +++ b/source/Entities/ProjectileEntity.h @@ -78,6 +78,7 @@ protected: // cEntity overrides: virtual void Tick(float a_Dt, cChunk & a_Chunk) override; virtual void HandlePhysics(float a_Dt, cChunk & a_Chunk) override; + virtual void SpawnOn(cClientHandle & a_Client) override; // tolua_begin } ; @@ -105,7 +106,7 @@ public: CLASS_PROTODEF(cArrowEntity); /// Creates a new arrow with psNoPickup state and default damage modifier coeff - cArrowEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d a_Speed); + cArrowEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed); /// Creates a new arrow as shot by a player, initializes it from the player object cArrowEntity(cPlayer & a_Player, double a_Force); @@ -137,12 +138,100 @@ protected: /// The coefficient applied to the damage that the arrow will deal, based on the bow enchantment. 2.0 for normal arrow double m_DamageCoeff; - // cEntity overrides: + // cProjectileEntity overrides: virtual void SpawnOn(cClientHandle & a_Client) override; // tolua_begin } ; + + + + +class cThrownEggEntity : + public cProjectileEntity +{ + typedef cProjectileEntity super; + +public: + + // tolua_end + + CLASS_PROTODEF(cThrownEggEntity); + + cThrownEggEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed); + +protected: + + // tolua_end + + // cProjectileEntity overrides: + virtual void OnHitSolidBlock(int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace) override; + + // tolua_begin + +} ; + + + + + +class cThrownEnderPearlEntity : + public cProjectileEntity +{ + typedef cProjectileEntity super; + +public: + + // tolua_end + + CLASS_PROTODEF(cThrownEnderPearlEntity); + + cThrownEnderPearlEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed); + +protected: + + // tolua_end + + // cProjectileEntity overrides: + virtual void OnHitSolidBlock(int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace) override; + + // tolua_begin + +} ; + + + + + +class cThrownSnowballEntity : + public cProjectileEntity +{ + typedef cProjectileEntity super; + +public: + + // tolua_end + + CLASS_PROTODEF(cThrownSnowballEntity); + + cThrownSnowballEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed); + +protected: + + // tolua_end + + // cProjectileEntity overrides: + virtual void OnHitSolidBlock(int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace) override; + + // tolua_begin + +} ; + + + + + // tolua_end diff --git a/source/Items/ItemHandler.cpp b/source/Items/ItemHandler.cpp index c0de4a6ec..2ae193d52 100644 --- a/source/Items/ItemHandler.cpp +++ b/source/Items/ItemHandler.cpp @@ -22,6 +22,7 @@ #include "ItemLighter.h" #include "ItemMinecart.h" #include "ItemPickaxe.h" +#include "ItemThrowable.h" #include "ItemRedstoneDust.h" #include "ItemRedstoneRepeater.h" #include "ItemSapling.h" @@ -88,12 +89,15 @@ cItemHandler *cItemHandler::CreateItemHandler(int a_ItemType) case E_ITEM_BREWING_STAND: return new cItemBrewingStandHandler(a_ItemType); case E_ITEM_CAULDRON: return new cItemCauldronHandler(a_ItemType); case E_ITEM_DYE: return new cItemDyeHandler(a_ItemType); + case E_ITEM_EGG: return new cItemEggHandler(); + case E_ITEM_ENDER_PEARL: return new cItemEnderPearlHandler(); case E_ITEM_FLINT_AND_STEEL: return new cItemLighterHandler(a_ItemType); case E_ITEM_FLOWER_POT: return new cItemFlowerPotHandler(a_ItemType); case E_ITEM_REDSTONE_DUST: return new cItemRedstoneDustHandler(a_ItemType); case E_ITEM_REDSTONE_REPEATER: return new cItemRedstoneRepeaterHandler(a_ItemType); case E_ITEM_SHEARS: return new cItemShearsHandler(a_ItemType); case E_ITEM_SIGN: return new cItemSignHandler(a_ItemType); + case E_ITEM_SNOWBALL: return new cItemSnowballHandler(); case E_ITEM_SPAWN_EGG: return new cItemSpawnEggHandler(a_ItemType); case E_ITEM_SUGARCANE: return new cItemSugarcaneHandler(a_ItemType); diff --git a/source/Items/ItemThrowable.h b/source/Items/ItemThrowable.h new file mode 100644 index 000000000..dacdb6157 --- /dev/null +++ b/source/Items/ItemThrowable.h @@ -0,0 +1,90 @@ + +// ItemThrowable.h + +// Declares the itemhandlers for throwable items: eggs, snowballs and ender pearls + + + + + +#pragma once + + + + + +class cItemThrowableHandler : + public cItemHandler +{ + typedef cItemHandler super; +public: + cItemThrowableHandler(int a_ItemType, cProjectileEntity::eKind a_ProjectileKind, double a_SpeedCoeff) : + super(a_ItemType), + m_ProjectileKind(a_ProjectileKind), + m_SpeedCoeff(a_SpeedCoeff) + { + } + + + virtual bool OnItemUse(cWorld * a_World, cPlayer * a_Player, const cItem & a_Item, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Dir) override + { + Vector3d Pos = a_Player->GetThrowStartPos(); + Vector3d Speed = a_Player->GetLookVector() * m_SpeedCoeff; + a_World->CreateProjectile(Pos.x, Pos.y, Pos.z, m_ProjectileKind, a_Player, &Speed); + return true; + } + +protected: + cProjectileEntity::eKind m_ProjectileKind; + double m_SpeedCoeff; +} ; + + + + + +class cItemEggHandler : + public cItemThrowableHandler +{ + typedef cItemThrowableHandler super; +public: + cItemEggHandler(void) : + super(E_ITEM_EGG, cProjectileEntity::pkEgg, 30) + { + } +} ; + + + + +class cItemSnowballHandler : + public cItemThrowableHandler +{ + typedef cItemThrowableHandler super; + +public: + cItemSnowballHandler(void) : + super(E_ITEM_SNOWBALL, cProjectileEntity::pkSnowball, 30) + { + } +} ; + + + + + +class cItemEnderPearlHandler : + public cItemThrowableHandler +{ + typedef cItemThrowableHandler super; + +public: + cItemEnderPearlHandler(void) : + super(E_ITEM_ENDER_PEARL, cProjectileEntity::pkEnderPearl, 30) + { + } +} ; + + + + From 1c5b5716338290fe402c6fbe824a86d799b40476 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Fri, 30 Aug 2013 19:37:28 +0200 Subject: [PATCH 3/6] AnvilStats: Ignoring the build folders --- Tools/AnvilStats/.gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Tools/AnvilStats/.gitignore b/Tools/AnvilStats/.gitignore index 4ed720fed..6832eb9f8 100644 --- a/Tools/AnvilStats/.gitignore +++ b/Tools/AnvilStats/.gitignore @@ -1,5 +1,7 @@ .xls Statistics.txt *.bmp +Debug/ +Release/ Profiling *.png From 32bc9693390c7a2b662ec55a17b338fe68a720eb Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Fri, 30 Aug 2013 19:38:21 +0200 Subject: [PATCH 4/6] AnvilStats: Added the callback for region begin and end. --- Tools/AnvilStats/AnvilStats.txt | 1 + Tools/AnvilStats/Callback.h | 12 +++++++++--- Tools/AnvilStats/Processor.cpp | 8 ++++++++ 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/Tools/AnvilStats/AnvilStats.txt b/Tools/AnvilStats/AnvilStats.txt index 19aa4f324..1d8130aa2 100644 --- a/Tools/AnvilStats/AnvilStats.txt +++ b/Tools/AnvilStats/AnvilStats.txt @@ -15,6 +15,7 @@ Possible usage: - count the per-chunk density of specific blocks - count the per-chunk density of dungeons, by measuring the number of zombie/skeleton/regularspider spawners - count the per-chunk-per-biome density of trees, by measuring the number of dirt-log vertical transitions, correlating to biome data + - draw a vertical map of the world based on a specific measured value (biome, elevation, ...) This project is Windows-only, although it shouldn't be too difficult to make it portable. diff --git a/Tools/AnvilStats/Callback.h b/Tools/AnvilStats/Callback.h index 83b330651..eed51a41c 100644 --- a/Tools/AnvilStats/Callback.h +++ b/Tools/AnvilStats/Callback.h @@ -22,17 +22,20 @@ class cParsedNBT; /** The base class for all chunk-processor callbacks, declares the interface. The processor calls each virtual function in the order they are declared here with the specified args. -If the function returns true, the processor moves on to next chunk and starts calling the callbacks again from start with -the new chunk data. +If the function returns true, the processor doesn't process the data item, moves on to the next chunk +and starts calling the callbacks again from start with the new chunk data. So if a statistics collector doesn't need data decompression at all, it can stop the processor from doing so early-enough and still get meaningful data. -A callback is guaranteed to run in a single thread and always the same thread. +A callback is guaranteed to run in a single thread and always the same thread for the same chunk. A callback is guaranteed to run on all chunks in a region and one region is guaranteed to be handled by only callback. */ class cCallback abstract { public: virtual ~cCallback() {} // Force a virtual destructor in each descendant + + /// Called when a new region file is about to be opened; by default allow the region + virtual bool OnNewRegion(int a_RegionX, int a_RegionZ) { return false; } /// Called to inform the stats module of the chunk coords for newly processing chunk virtual bool OnNewChunk(int a_ChunkX, int a_ChunkZ) = 0; @@ -118,6 +121,9 @@ public: int a_TicksLeft, int a_PosX, int a_PosY, int a_PosZ ) { return true; } + + /// Called after the entire region file has been processed. No more callbacks for this region will be called. No processing by default + virtual void OnRegionFinished(int a_RegionX, int a_RegionZ) {} } ; typedef std::vector cCallbacks; diff --git a/Tools/AnvilStats/Processor.cpp b/Tools/AnvilStats/Processor.cpp index e7f7eb21d..8e1cc4c4b 100644 --- a/Tools/AnvilStats/Processor.cpp +++ b/Tools/AnvilStats/Processor.cpp @@ -76,6 +76,12 @@ void cProcessor::cThread::ProcessFile(const AString & a_FileName) return; } + if (m_Callback.OnNewRegion(RegionX, RegionZ)) + { + // Callback doesn't want the region file processed + return; + } + cFile f; if (!f.Open(a_FileName, cFile::fmRead)) { @@ -92,6 +98,8 @@ void cProcessor::cThread::ProcessFile(const AString & a_FileName) } ProcessFileData(FileContents.data(), FileContents.size(), RegionX * 32, RegionZ * 32); + + m_Callback.OnRegionFinished(RegionX, RegionZ); } From b1f8b6e4c47556799f7fe753c87960f60d003153 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Fri, 30 Aug 2013 20:45:29 +0200 Subject: [PATCH 5/6] AnvilStats: Callbacks can now use CALLBACK_CONTINUE and CALLBACK_ABORT instead of bool return values. This makes the code slightly easier to understand. --- Tools/AnvilStats/Callback.h | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/Tools/AnvilStats/Callback.h b/Tools/AnvilStats/Callback.h index eed51a41c..eda4a8478 100644 --- a/Tools/AnvilStats/Callback.h +++ b/Tools/AnvilStats/Callback.h @@ -32,37 +32,43 @@ A callback is guaranteed to run on all chunks in a region and one region is guar class cCallback abstract { public: + enum + { + CALLBACK_CONTINUE = false, + CALLBACK_ABORT = true, + } ; + virtual ~cCallback() {} // Force a virtual destructor in each descendant /// Called when a new region file is about to be opened; by default allow the region - virtual bool OnNewRegion(int a_RegionX, int a_RegionZ) { return false; } + virtual bool OnNewRegion(int a_RegionX, int a_RegionZ) { return CALLBACK_CONTINUE; } /// Called to inform the stats module of the chunk coords for newly processing chunk virtual bool OnNewChunk(int a_ChunkX, int a_ChunkZ) = 0; /// Called to inform about the chunk's data offset in the file (chunk mini-header), the number of sectors it uses and the timestamp field value - virtual bool OnHeader(int a_FileOffset, unsigned char a_NumSectors, int a_Timestamp) { return true; } + virtual bool OnHeader(int a_FileOffset, unsigned char a_NumSectors, int a_Timestamp) { return CALLBACK_ABORT; } /// Called to inform of the compressed chunk data size and position in the file (offset from file start to the actual data) - virtual bool OnCompressedDataSizePos(int a_CompressedDataSize, int a_DataOffset, char a_CompressionMethod) { return true; } + virtual bool OnCompressedDataSizePos(int a_CompressedDataSize, int a_DataOffset, char a_CompressionMethod) { return CALLBACK_ABORT; } /// Just in case you wanted to process the NBT yourself ;) - virtual bool OnDecompressedData(const char * a_DecompressedNBT, int a_DataSize) { return true; } + virtual bool OnDecompressedData(const char * a_DecompressedNBT, int a_DataSize) { return CALLBACK_ABORT; } /// The chunk's NBT should specify chunk coords, these are sent here: - virtual bool OnRealCoords(int a_ChunkX, int a_ChunkZ) { return true; } + virtual bool OnRealCoords(int a_ChunkX, int a_ChunkZ) { return CALLBACK_ABORT; } /// The chunk contains a LastUpdate value specifying the last tick in which it was saved. - virtual bool OnLastUpdate(Int64 a_LastUpdate) { return true; } + virtual bool OnLastUpdate(Int64 a_LastUpdate) { return CALLBACK_ABORT; } - virtual bool OnTerrainPopulated(bool a_Populated) { return true; } + virtual bool OnTerrainPopulated(bool a_Populated) { return CALLBACK_ABORT; } - virtual bool OnBiomes(const unsigned char * a_BiomeData) { return true; } + virtual bool OnBiomes(const unsigned char * a_BiomeData) { return CALLBACK_ABORT; } /** Called when a heightmap for the chunk is read from the file. Note that the heightmap is given in big-endian ints, so if you want it, you need to ntohl() it first! */ - virtual bool OnHeightMap(const int * a_HeightMapBE) { return true; } + virtual bool OnHeightMap(const int * a_HeightMapBE) { return CALLBACK_ABORT; } /** If there is data for the section, this callback is called; otherwise OnEmptySection() is called instead. All OnSection() callbacks are called first, and only then all the remaining sections are reported in OnEmptySection(). @@ -74,16 +80,16 @@ public: const NIBBLETYPE * a_BlockMeta, const NIBBLETYPE * a_BlockLight, const NIBBLETYPE * a_BlockSkyLight - ) { return true; } + ) { return CALLBACK_ABORT; } /** If there is no data for a section, this callback is called; otherwise OnSection() is called instead. OnEmptySection() callbacks are called after all OnSection() callbacks. */ - virtual bool OnEmptySection(unsigned char a_Y) { return false; } + virtual bool OnEmptySection(unsigned char a_Y) { return CALLBACK_CONTINUE; } /** Called after all sections have been processed via either OnSection() or OnEmptySection(). */ - virtual bool OnSectionsFinished(void) { return true; } + virtual bool OnSectionsFinished(void) { return CALLBACK_ABORT; } /** Called for each entity in the chunk. Common parameters are parsed from the NBT. @@ -101,7 +107,7 @@ public: char a_IsOnGround, cParsedNBT & a_NBT, int a_NBTTag - ) { return true; } + ) { return CALLBACK_ABORT; } /** Called for each tile entity in the chunk. Common parameters are parsed from the NBT. @@ -113,14 +119,14 @@ public: int a_PosX, int a_PosY, int a_PosZ, cParsedNBT & a_NBT, int a_NBTTag - ) { return true; } + ) { return CALLBACK_ABORT; } /// Called for each tile tick in the chunk virtual bool OnTileTick( int a_BlockType, int a_TicksLeft, int a_PosX, int a_PosY, int a_PosZ - ) { return true; } + ) { return CALLBACK_ABORT; } /// Called after the entire region file has been processed. No more callbacks for this region will be called. No processing by default virtual void OnRegionFinished(int a_RegionX, int a_RegionZ) {} From 7f4c880147719d7b2d3cd97c68ad5af76764042b Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Fri, 30 Aug 2013 20:46:16 +0200 Subject: [PATCH 6/6] AnvilStats: Implemented a cImageComposingCallback class. This will ease the creation of callbacks that produce per-region images of stuff. --- Tools/AnvilStats/AnvilStats.vcproj | 8 + Tools/AnvilStats/ImageComposingCallback.cpp | 189 ++++++++++++++++++++ Tools/AnvilStats/ImageComposingCallback.h | 95 ++++++++++ 3 files changed, 292 insertions(+) create mode 100644 Tools/AnvilStats/ImageComposingCallback.cpp create mode 100644 Tools/AnvilStats/ImageComposingCallback.h diff --git a/Tools/AnvilStats/AnvilStats.vcproj b/Tools/AnvilStats/AnvilStats.vcproj index ed4ffa9a5..b6000ea3e 100644 --- a/Tools/AnvilStats/AnvilStats.vcproj +++ b/Tools/AnvilStats/AnvilStats.vcproj @@ -321,6 +321,14 @@ RelativePath=".\HeightMap.h" > + + + + diff --git a/Tools/AnvilStats/ImageComposingCallback.cpp b/Tools/AnvilStats/ImageComposingCallback.cpp new file mode 100644 index 000000000..138821698 --- /dev/null +++ b/Tools/AnvilStats/ImageComposingCallback.cpp @@ -0,0 +1,189 @@ + +// ImageComposingCallback.cpp + +// Implements the cImageComposingCallback class that implements a subset of cCallback for composing per-region images + +#include "Globals.h" +#include "ImageComposingCallback.h" + + + + + +cImageComposingCallback::cImageComposingCallback(const AString & a_FileNamePrefix) : + m_FileNamePrefix(a_FileNamePrefix), + m_CurrentRegionX(INVALID_REGION_COORD), + m_CurrentRegionZ(INVALID_REGION_COORD), + m_ImageData(new int[32 * 16 * 32 * 16]) +{ +} + + + + + +cImageComposingCallback::~cImageComposingCallback() +{ + delete[] m_ImageData; +} + + + + + +bool cImageComposingCallback::OnNewRegion(int a_RegionX, int a_RegionZ) +{ + ASSERT(m_CurrentRegionX == INVALID_REGION_COORD); + ASSERT(m_CurrentRegionZ == INVALID_REGION_COORD); // Has any previous region been finished properly? + + m_CurrentRegionX = a_RegionX; + m_CurrentRegionZ = a_RegionZ; + OnEraseImage(); + + return CALLBACK_CONTINUE; +} + + + + + +void cImageComposingCallback::OnRegionFinished(int a_RegionX, int a_RegionZ) +{ + ASSERT(m_CurrentRegionX != INVALID_REGION_COORD); + ASSERT(m_CurrentRegionZ != INVALID_REGION_COORD); // Has a region been started properly? + ASSERT(m_CurrentRegionX == a_RegionX); + ASSERT(m_CurrentRegionZ == a_RegionZ); // Is it the same region that has been started? + + AString FileName = GetFileName(a_RegionX, a_RegionZ); + if (!FileName.empty()) + { + OnBeforeImageSaved(a_RegionX, a_RegionZ, FileName); + SaveImage(FileName); + OnAfterImageSaved(a_RegionX, a_RegionZ, FileName); + } + + m_CurrentRegionX = INVALID_REGION_COORD; + m_CurrentRegionZ = INVALID_REGION_COORD; +} + + + + + +AString cImageComposingCallback::GetFileName(int a_RegionX, int a_RegionZ) +{ + return Printf("%s.%d.%d", m_FileNamePrefix.c_str(), a_RegionX, a_RegionZ); +} + + + + + +void cImageComposingCallback::OnEraseImage(void) +{ + // By default erase the image to black: + EraseImage(0); +} + + + + + +void cImageComposingCallback::EraseImage(int a_Color) +{ + for (int i = 0; i < PIXEL_COUNT; i++) + { + m_ImageData[i] = a_Color; + } +} + + + + + +void cImageComposingCallback::EraseChunk(int a_Color, int a_RelChunkX, int a_RelChunkZ) +{ + int Base = a_RelChunkZ * IMAGE_HEIGHT + a_RelChunkX * 16; + for (int v = 0; v < 16; v++) + { + int BaseV = Base + v * IMAGE_HEIGHT; + for (int u = 0; u < 16; u++) + { + m_ImageData[BaseV + u] = a_Color; + } + } // for y +} + + + + + +void cImageComposingCallback::SetPixel(int a_RelU, int a_RelV, int a_Color) +{ + ASSERT((a_RelU >= 0) && (a_RelU < IMAGE_WIDTH)); + ASSERT((a_RelV >= 0) && (a_RelV < IMAGE_HEIGHT)); + + m_ImageData[a_RelU + IMAGE_WIDTH * a_RelV] = a_Color; +} + + + + + +int cImageComposingCallback::GetPixel(int a_RelU, int a_RelV) +{ + if ((a_RelU < 0) || (a_RelU >= IMAGE_WIDTH) || (a_RelV < 0) || (a_RelV >= IMAGE_HEIGHT)) + { + // Outside the image data + return -1; + } + + return m_ImageData[a_RelU + IMAGE_WIDTH * a_RelV]; +} + + + + + + +void cImageComposingCallback::SetPixelURow(int a_RelUStart, int a_RelV, int a_CountU, int * a_Pixels) +{ + ASSERT((a_RelUStart >= 0) && (a_RelUStart + a_CountU < IMAGE_WIDTH)); + ASSERT((a_RelV >= 0) && (a_RelV < IMAGE_HEIGHT)); + ASSERT(a_Pixels != NULL); + + int Base = a_RelUStart + a_RelV * IMAGE_WIDTH; + for (int u = 0; u < a_CountU; u++) + { + m_ImageData[Base + u] = a_Pixels[u]; + } +} + + + + + +void cImageComposingCallback::SaveImage(const AString & a_FileName) +{ + cFile f(a_FileName, cFile::fmWrite); + if (!f.IsOpen()) + { + return; + } + + // Header for BMP files (is the same for the same-size files) + static const unsigned char BMPHeader[] = + { + 0x42, 0x4D, 0x36, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x28, 0x00, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x13, 0x0B, 0x00, 0x00, 0x13, 0x0B, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + } ; + + f.Write(BMPHeader, sizeof(BMPHeader)); + f.Write(m_ImageData, PIXEL_COUNT * 4); +} + + + + diff --git a/Tools/AnvilStats/ImageComposingCallback.h b/Tools/AnvilStats/ImageComposingCallback.h new file mode 100644 index 000000000..c04dc869f --- /dev/null +++ b/Tools/AnvilStats/ImageComposingCallback.h @@ -0,0 +1,95 @@ + +// ImageComposingCallback + +// Declares the cImageComposingCallback class that implements a subset of cCallback for composing per-region images + + + + + +#pragma once + +#include "Callback.h" + + + + +/** Implements the plumbing for composing per-region images from multiple chunks. +To use this class, create a descendant that writes the image data using +SetPixel() or SetPixelURow() functions. + +For the purpose of this class the image data is indexed U (horz) * V (vert), to avoid confusion with other coords. +The image is a 32bpp raw imagedata, written into a BMP file. +*/ +class cImageComposingCallback : + public cCallback +{ +public: + enum + { + INVALID_REGION_COORD = 99999, ///< Used for un-assigned region coords + IMAGE_WIDTH = 32 * 16, + IMAGE_HEIGHT = 32 * 16, + PIXEL_COUNT = IMAGE_WIDTH * IMAGE_HEIGHT, ///< Total pixel count of the image data + } ; + + cImageComposingCallback(const AString & a_FileNamePrefix); + virtual ~cImageComposingCallback(); + + // cCallback overrides: + virtual bool OnNewRegion(int a_RegionX, int a_RegionZ) override; + virtual void OnRegionFinished(int a_RegionX, int a_RegionZ) override; + + // New introduced overridable functions: + + /// Called when a file is about to be saved, to generate the filename + virtual AString GetFileName(int a_RegionX, int a_RegionZ); + + /// Called before the file is saved + virtual void OnBeforeImageSaved(int a_RegionX, int a_RegionZ, const AString & a_FileName) {} + + /// Called after the image is saved to a file + virtual void OnAfterImageSaved(int a_RegionX, int a_RegionZ, const AString & a_FileName) {} + + /// Called when a new region is beginning, to erase the image data + virtual void OnEraseImage(void); + + // Functions for manipulating the image: + + /// Erases the entire image with the specified color + void EraseImage(int a_Color); + + /// Erases the specified chunk's portion of the image with the specified color. Note that chunk coords are relative to the current region + void EraseChunk(int a_Color, int a_RelChunkX, int a_RelChunkZ); + + /// Returns the current region X coord + int GetCurrentRegionX(void) const { return m_CurrentRegionX; } + + /// Returns the current region Z coord + int GetCurrentRegionZ(void) const { return m_CurrentRegionZ; } + + /// Sets the pixel at the specified UV coords to the specified color + void SetPixel(int a_RelU, int a_RelV, int a_Color); + + /// Returns the color of the pixel at the specified UV coords; -1 if outside + int GetPixel(int a_RelU, int a_RelV); + + /// Sets a row of pixels. a_Pixels is expected to be a_CountU pixels wide. a_RelUStart + a_CountU is assumed less than image width + void SetPixelURow(int a_RelUStart, int a_RelV, int a_CountU, int * a_Pixels); + +protected: + /// Prefix for the filenames, when generated by the default GetFileName() function + AString m_FileNamePrefix; + + /// Coords of the currently processed region + int m_CurrentRegionX, m_CurrentRegionZ; + + /// Raw image data; 1 MiB worth of data, therefore unsuitable for stack allocation. [u + IMAGE_WIDTH * v] + int * m_ImageData; + + void SaveImage(const AString & a_FileName); +} ; + + + +