Posts: 33
Threads: 10
Joined: Dec 2016
Thanks: 10
Given 0 thank(s) in 0 post(s)
Hi there,
i have make my own map with WorldPainter. Now i would write a plugin for regenerate chunks when there are modify by a player.
How i can make this? I cant regenerate with seed. Must i copy the chunks from a copy of my map?
moiko89
Posts: 4,629
Threads: 115
Joined: Dec 2011
Thanks: 693
Given 494 thank(s) in 423 post(s)
If you want to prevent a player from changing chunks you can use the HOOK_PLAYER_RIGHT_CLICK and HOOK_PLAYER_LEFT_CLICK hooks.
Posts: 6,485
Threads: 176
Joined: Jan 2012
Thanks: 131
Given 1075 thank(s) in 852 post(s)
There are basically four options:
- don't let the players modify the world at all
- keep a copy of the world and copy from there
- keep track of all changes made by the players and undo those
- use the Forgetful world storage schema
The first one is what NiLSPACE was hinting at.
The second is a perfect example of using multiworld as an advantage - make Cuberite load both worlds, but don't let players into the "backup" world. Then simply copy any area from the backup to the main world.
Third option is the most versatile, but perhaps the most difficult to implement. An extra advantage would be the ability to selectively undo only a part of the changes.
If I were to do this, I would first try to use the fourth approach; if that wouldn't satisfy my needs, then approach number two.
Posts: 33
Threads: 10
Joined: Dec 2016
Thanks: 10
Given 0 thank(s) in 0 post(s)
05-14-2017, 10:01 PM
(This post was last modified: 05-14-2017, 11:08 PM by moiko89.)
(12-17-2016, 10:42 PM)xoft Wrote: - keep a copy of the world and copy from there
The second is a perfect example of using multiworld as an advantage - make Cuberite load both worlds, but don't let players into the "backup" world. Then simply copy any area from the backup to the main world.
At first i think the second option is the best.
How i can log if a entity has modify a chunk?
How i can copy the chunk from backup world to main world?
Okay, i looked in the WorldEdit Plugin, is this the best way?
PHP Code: function copy(World,chX,chZ) print("Start Copy for:",chX,chZ)
local startX = math.floor(chX * 16) local endX = math.floor(chX * 16) + 16 local startZ = math.floor(chZ * 16) local endZ = math.floor(chZ * 16) + 16
print(startX,endX,startZ,endZ)
for X = startX, endX do for Y = 0, 255 do for Z = startZ, endZ do local BlockType = World:GetBlock(X, Y, Z) if(BlockType ~= 0) then local BlockMeta = World:GetBlockMeta(X, Y, Z) print("Copy Block",X,Y,Z,"BlockID;", BlockType) -- Test Copy to the next X Chunk World:SetBlock(X+16, Y, Z, BlockType, BlockMeta, false) end end end end end
I doesnt find a function and hook in wiki.
Posts: 6,485
Threads: 176
Joined: Jan 2012
Thanks: 131
Given 1075 thank(s) in 852 post(s)
05-15-2017, 05:18 AM
(This post was last modified: 05-15-2017, 05:18 AM by xoft.)
In the Hooks section of the API documentation, there's the list of hooks Cuberite supports. I think you want the HOOK_PLAYER_BROKEN_BLOCK and HOOK_PLAYER_PLACED_BLOCK.
https://api.cuberite.org/#hooks
Copying the chunk one block at a time will be slow. Instead, use a cBlockArea to read the entire chunk in one API call and write it in another single API call.
Note, though, that the cBlockArea currently doesn't support block entities nor regular entities, so your plugin will have to process those separately.
Posts: 33
Threads: 10
Joined: Dec 2016
Thanks: 10
Given 0 thank(s) in 0 post(s)
(05-15-2017, 05:18 AM)xoft Wrote: In the Hooks section of the API documentation, there's the list of hooks Cuberite supports. I think you want the HOOK_PLAYER_BROKEN_BLOCK and HOOK_PLAYER_PLACED_BLOCK.
https://api.cuberite.org/#hooks
Copying the chunk one block at a time will be slow. Instead, use a cBlockArea to read the entire chunk in one API call and write it in another single API call.
Note, though, that the cBlockArea currently doesn't support block entities nor regular entities, so your plugin will have to process those separately.
Do you have an simple example for copy with cBlockArea?
Posts: 6,485
Threads: 176
Joined: Jan 2012
Thanks: 131
Given 1075 thank(s) in 852 post(s)
The WorldEdit plugin has a //copy and //paste commands that basically do what you want to do.
Simply put, you need to create a cBlockArea object, Read data into it (from within a cWorld:ChunkStay() to make sure the chunks are loaded) and then Write() it to the destination, again in a cWorld:ChunkStay(). Note that it's a bad idea to call a ChunkStay from another world's ChunkStay handler, because that could result in a deadlock. Use cWorld:QueueTask on the second world to avoid the deadlock.
local ba = cBlockArea()
srcWorld:ChunkStay(chunkCoords, nil,
function()
ba:Read(srcWorld, ...)
dstWorld:QueueTask(
function()
ba:Write(dstWorld, ...)
ba:Clear()
end
)
end
)
Posts: 33
Threads: 10
Joined: Dec 2016
Thanks: 10
Given 0 thank(s) in 0 post(s)
05-17-2017, 05:04 AM
(This post was last modified: 05-17-2017, 07:44 AM by xoft.)
Hi,
function MyOnPlayerRightClick(Player, BlockX, BlockY, BlockZ, BlockFace, CursorX, CursorY, CursorZ) -- See API docs for parameters of all hooks
local chunkx = math.floor(BlockX / 16)
local chunkz = math.floor(BlockZ / 16)
SourceWorld = cRoot:Get():GetWorld(Player:GetWorld():GetName() .. '_backup')
DestWorld = Player:GetWorld()
--print(backUpWorld:GetName())
local ba = cBlockArea()
local startX = math.floor(chunkx * 16)
local endX = math.floor(chunkx * 16) + 15
local startZ = math.floor(chunkz * 16)
local endZ = math.floor(chunkz * 16) + 15
local cubo = cCuboid(startX,1,startZ,endX,255,endZ)
SourceWorld:ChunkStay({{chunkx, chunkz}}, nil,
function()
ba:Read(SourceWorld, cubo)
DestWorld:QueueTask(
function()
ba:Write(DestWorld, startX, 2, startZ)
ba:Clear()
end
)
end
)
end
and my terminal says:
Code: [20:56:44] cChunk::WriteBlockArea(): unsupported datatype request, can write only types + metas (0x3), requested 0x0. Ignoring.
Whats my fail?
Posts: 6,485
Threads: 176
Joined: Jan 2012
Thanks: 131
Given 1075 thank(s) in 852 post(s)
05-17-2017, 07:56 AM
(This post was last modified: 05-17-2017, 07:56 AM by xoft.)
That should work. For some reason it seems that the blockarea is not read from the source world (you should check for failures - it returns a boolean).
For troubleshooting, what does ba:GetDataValues() return after the Read() call?
Or it could be some weird API binding failure, Write() function mis-interpreting one of its parameters. Try using ba:Write(DestWorld, startX, 2, startZ, cBlockArea.baTypes + cBlockArea.baMetas)
Also, I forgot that there needs to be one more ChunkStay, for the DestWorld, inside the DestWorld:QueueTask()'s callback:
...
DestWorld:QueueTask(
function()
DestWorld:ChunkStay({{chunkx, chunkz}}, nil,
function()
ba:Write(DestWorld, startX, 2, startZ)
ba:Clear()
end -- ChunkStay callback
)
end -- QueueTask callback
)
...
|