While @BassetHound has given a nice and easy solution, I'd like to provide a more powerful and robust solution, in case the protected area is not adequately described by a sphere of radius R. For example, your server might have a main road that is off-limits, but players are encouraged to build houses next to it, or catacombs beneath.
To do so, we'll set up a scoreboard objective, which will be changed based on the location of the player, allowing us to define the protected area with multiple different commands, thus allowing arbitrary shapes.
Start by setting up the objective itself, let's call it inTown
:
scoreboard objectives add inTown dummy
Now, create a fill clock and run the following commands
scoreboard players set @a inTown 0
scoreboard players set @a[score_inTown=0,x=X1,y=Y1,z=Z1,dx=dX1,dy=dY1,dz=dZ1] inTown 1
scoreboard players set @a[score_inTown=0,x=X",y=Y2,z=Z2,dx=dX2,dy=dY2,dz=dZ2] inTown 1
...
scoreboard players set @a[score_inTown=0,x=XN,y=YN,z=ZN,dx=dXN,dy=dYN,dz=dZN] inTown 1
Each of these will define an area from (Xn,Yn,Zn)
to (Xn+dXn,Yn+dYn,Zn+dZn)
as part of your town, and set the score for players in that area to 1. If a player is not in any of these areas, his score will remain at 0 instead.
Of course, you can use other target selector arguments to define your area as well.
Now, add two commands to the end of your clock to set the gamemodes correctly:
gamemode 0 @a[score_inTown=0,m=2]
gamemode 2 @a[score_inTown_min=1,m=0]
Adding the m
selector ensures that gamemodes are only set when appropriate. Players in spectator or creative mode are not affected. Just before changing the gamemode, you could use the same target selectors as above to inform your players of the change using the tellraw
or title
commands.