Merge branch 'save-world'

Third time's the charm!
This commit is contained in:
OLEGSHA 2021-08-24 01:38:22 +03:00
commit 0ccc108ddd
Signed by: OLEGSHA
GPG Key ID: E57A4B08D64AFF7A
22 changed files with 925 additions and 185 deletions

View File

@ -15,21 +15,32 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package ru.windcorp.progressia; package ru.windcorp.progressia;
import ru.windcorp.progressia.client.ClientProxy;
import ru.windcorp.progressia.client.graphics.GUI;
import ru.windcorp.progressia.common.util.crash.CrashReports; import ru.windcorp.progressia.common.util.crash.CrashReports;
import ru.windcorp.progressia.common.util.crash.analyzers.OutOfMemoryAnalyzer; import ru.windcorp.progressia.common.util.crash.analyzers.OutOfMemoryAnalyzer;
import ru.windcorp.progressia.common.util.crash.providers.*; import ru.windcorp.progressia.common.util.crash.providers.*;
import ru.windcorp.progressia.test.LayerTitle;
public class ProgressiaLauncher { public class ProgressiaLauncher {
public static String[] arguments; public static String[] arguments;
private static ClientProxy proxy;
public static void launch(String[] args, Proxy proxy) { public static void launch(String[] args, ClientProxy inProxy) {
arguments = args.clone(); arguments = args.clone();
setupCrashReports(); setupCrashReports();
proxy.initialize();
inProxy.initialize();
proxy = inProxy;
GUI.addTopLayer(new LayerTitle("Title"));
}
public static void play() {
proxy.setupServer();
} }
private static void setupCrashReports() { private static void setupCrashReports() {

View File

@ -15,7 +15,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package ru.windcorp.progressia.client; package ru.windcorp.progressia.client;
import ru.windcorp.progressia.Proxy; import ru.windcorp.progressia.Proxy;
@ -38,7 +38,9 @@ public class ClientProxy implements Proxy {
@Override @Override
public void initialize() { public void initialize() {
GraphicsBackend.initialize(); GraphicsBackend.initialize();
try { try {
RenderTaskQueue.waitAndInvoke(FlatRenderProgram::init); RenderTaskQueue.waitAndInvoke(FlatRenderProgram::init);
RenderTaskQueue.waitAndInvoke(WorldRenderProgram::init); RenderTaskQueue.waitAndInvoke(WorldRenderProgram::init);
@ -58,10 +60,12 @@ public class ClientProxy implements Proxy {
AudioSystem.initialize(); AudioSystem.initialize();
ServerState.startServer();
ClientState.connectToLocalServer();
TestMusicPlayer.start(); TestMusicPlayer.start();
} }
public void setupServer() {
ServerState.startServer();
ClientState.connectToLocalServer();
}
} }

View File

@ -15,15 +15,18 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package ru.windcorp.progressia.client; package ru.windcorp.progressia.client;
import ru.windcorp.progressia.client.comms.localhost.LocalServerCommsChannel; import ru.windcorp.progressia.client.comms.localhost.LocalServerCommsChannel;
import ru.windcorp.progressia.client.graphics.GUI; import ru.windcorp.progressia.client.graphics.GUI;
import ru.windcorp.progressia.client.graphics.Layer;
import ru.windcorp.progressia.client.graphics.world.LayerWorld; import ru.windcorp.progressia.client.graphics.world.LayerWorld;
import ru.windcorp.progressia.common.world.DefaultWorldData; import ru.windcorp.progressia.common.world.DefaultWorldData;
import ru.windcorp.progressia.client.localization.MutableStringLocalized;
import ru.windcorp.progressia.server.ServerState; import ru.windcorp.progressia.server.ServerState;
import ru.windcorp.progressia.test.LayerAbout; import ru.windcorp.progressia.test.LayerAbout;
import ru.windcorp.progressia.test.LayerTestText;
import ru.windcorp.progressia.test.LayerTestUI; import ru.windcorp.progressia.test.LayerTestUI;
import ru.windcorp.progressia.test.TestContent; import ru.windcorp.progressia.test.TestContent;
@ -52,11 +55,39 @@ public class ClientState {
channel.connect(TestContent.PLAYER_LOGIN); channel.connect(TestContent.PLAYER_LOGIN);
setInstance(client); setInstance(client);
displayLoadingScreen();
GUI.addBottomLayer(new LayerWorld(client)); }
GUI.addTopLayer(new LayerTestUI());
GUI.addTopLayer(new LayerAbout());
private static void displayLoadingScreen() {
GUI.addTopLayer(new LayerTestText("Text", new MutableStringLocalized("LayerText.Load"), layer -> {
Client client = ClientState.getInstance();
// TODO refacetor and remove
if (client != null) {
client.getComms().processPackets();
}
if (client != null && client.getLocalPlayer().hasEntity()) {
GUI.removeLayer(layer);
// TODO refactor, this shouldn't be here
LayerWorld layerWorld = new LayerWorld(client);
LayerTestUI layerUI = new LayerTestUI();
LayerAbout layerAbout = new LayerAbout();
GUI.addBottomLayer(layerWorld);
GUI.addTopLayer(layerUI);
GUI.addTopLayer(layerAbout);
}
}));
}
public static void disconnectFromLocalServer() {
getInstance().getComms().disconnect();
for (Layer layer : GUI.getLayers()) {
GUI.removeLayer(layer);
}
} }
private ClientState() { private ClientState() {

View File

@ -15,7 +15,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package ru.windcorp.progressia.client.comms.localhost; package ru.windcorp.progressia.client.comms.localhost;
import java.io.IOException; import java.io.IOException;

View File

@ -15,12 +15,13 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package ru.windcorp.progressia.client.comms.localhost; package ru.windcorp.progressia.client.comms.localhost;
import ru.windcorp.progressia.client.comms.ServerCommsChannel; import ru.windcorp.progressia.client.comms.ServerCommsChannel;
import ru.windcorp.progressia.common.comms.packets.Packet; import ru.windcorp.progressia.common.comms.packets.Packet;
import ru.windcorp.progressia.server.Server; import ru.windcorp.progressia.server.Server;
import ru.windcorp.progressia.server.ServerState;
public class LocalServerCommsChannel extends ServerCommsChannel { public class LocalServerCommsChannel extends ServerCommsChannel {
@ -54,7 +55,7 @@ public class LocalServerCommsChannel extends ServerCommsChannel {
@Override @Override
public void disconnect() { public void disconnect() {
// Do nothing ServerState.getInstance().getClientManager().disconnectClient(localClient);
} }
} }

View File

@ -15,12 +15,13 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package ru.windcorp.progressia.client.graphics; package ru.windcorp.progressia.client.graphics;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Objects;
import com.google.common.eventbus.Subscribe; import com.google.common.eventbus.Subscribe;
@ -58,6 +59,7 @@ public class GUI {
} }
public static void addBottomLayer(Layer layer) { public static void addBottomLayer(Layer layer) {
Objects.requireNonNull(layer, "layer");
modify(layers -> { modify(layers -> {
layers.add(layer); layers.add(layer);
layer.onAdded(); layer.onAdded();
@ -65,6 +67,7 @@ public class GUI {
} }
public static void addTopLayer(Layer layer) { public static void addTopLayer(Layer layer) {
Objects.requireNonNull(layer, "layer");
modify(layers -> { modify(layers -> {
layers.add(0, layer); layers.add(0, layer);
layer.onAdded(); layer.onAdded();
@ -72,6 +75,7 @@ public class GUI {
} }
public static void removeLayer(Layer layer) { public static void removeLayer(Layer layer) {
Objects.requireNonNull(layer, "layer");
modify(layers -> { modify(layers -> {
layers.remove(layer); layers.remove(layer);
layer.onRemoved(); layer.onRemoved();
@ -88,33 +92,33 @@ public class GUI {
public static void render() { public static void render() {
synchronized (LAYERS) { synchronized (LAYERS) {
if (!MODIFICATION_QUEUE.isEmpty()) { if (!MODIFICATION_QUEUE.isEmpty()) {
MODIFICATION_QUEUE.forEach(action -> action.affect(LAYERS)); MODIFICATION_QUEUE.forEach(action -> action.affect(LAYERS));
MODIFICATION_QUEUE.clear(); MODIFICATION_QUEUE.clear();
boolean isMouseCurrentlyCaptured = GraphicsInterface.isMouseCaptured(); boolean isMouseCurrentlyCaptured = GraphicsInterface.isMouseCaptured();
Layer.CursorPolicy policy = Layer.CursorPolicy.REQUIRE; Layer.CursorPolicy policy = Layer.CursorPolicy.REQUIRE;
for (Layer layer : LAYERS) { for (Layer layer : LAYERS) {
Layer.CursorPolicy currentPolicy = layer.getCursorPolicy(); Layer.CursorPolicy currentPolicy = layer.getCursorPolicy();
if (currentPolicy != Layer.CursorPolicy.INDIFFERENT) { if (currentPolicy != Layer.CursorPolicy.INDIFFERENT) {
policy = currentPolicy; policy = currentPolicy;
break; break;
} }
} }
boolean shouldCaptureMouse = (policy == Layer.CursorPolicy.FORBID); boolean shouldCaptureMouse = (policy == Layer.CursorPolicy.FORBID);
if (shouldCaptureMouse != isMouseCurrentlyCaptured) { if (shouldCaptureMouse != isMouseCurrentlyCaptured) {
GraphicsInterface.setMouseCaptured(shouldCaptureMouse); GraphicsInterface.setMouseCaptured(shouldCaptureMouse);
} }
} }
for (int i = LAYERS.size() - 1; i >= 0; --i) { for (int i = LAYERS.size() - 1; i >= 0; --i) {
LAYERS.get(i).render(); LAYERS.get(i).render();
} }
} }
} }

View File

@ -37,15 +37,15 @@ import ru.windcorp.progressia.client.graphics.gui.layout.LayoutAlign;
import ru.windcorp.progressia.client.graphics.input.KeyEvent; import ru.windcorp.progressia.client.graphics.input.KeyEvent;
public abstract class BasicButton extends Component { public abstract class BasicButton extends Component {
private final Label label; private final Label label;
private boolean isPressed = false; private boolean isPressed = false;
private final Collection<Consumer<BasicButton>> actions = Collections.synchronizedCollection(new ArrayList<>()); private final Collection<Consumer<BasicButton>> actions = Collections.synchronizedCollection(new ArrayList<>());
public BasicButton(String name, String label, Font labelFont) { public BasicButton(String name, Label label) {
super(name); super(name);
this.label = new Label(name + ".Label", labelFont, label); this.label = label;
setLayout(new LayoutAlign(10)); setLayout(new LayoutAlign(10));
addChild(this.label); addChild(this.label);
@ -59,8 +59,8 @@ public abstract class BasicButton extends Component {
return false; return false;
} else if ( } else if (
e.isLeftMouseButton() || e.isLeftMouseButton() ||
e.getKey() == GLFW.GLFW_KEY_SPACE || e.getKey() == GLFW.GLFW_KEY_SPACE ||
e.getKey() == GLFW.GLFW_KEY_ENTER e.getKey() == GLFW.GLFW_KEY_ENTER
) { ) {
setPressed(e.isPress()); setPressed(e.isPress());
return true; return true;
@ -68,9 +68,9 @@ public abstract class BasicButton extends Component {
return false; return false;
} }
}); });
addListener(new Object() { addListener(new Object() {
// Release when losing focus // Release when losing focus
@Subscribe @Subscribe
public void onFocusChange(FocusEvent e) { public void onFocusChange(FocusEvent e) {
@ -78,7 +78,7 @@ public abstract class BasicButton extends Component {
setPressed(false); setPressed(false);
} }
} }
// Release when hover ends // Release when hover ends
@Subscribe @Subscribe
public void onHoverEnded(HoverEvent e) { public void onHoverEnded(HoverEvent e) {
@ -86,7 +86,7 @@ public abstract class BasicButton extends Component {
setPressed(false); setPressed(false);
} }
} }
// Release when disabled // Release when disabled
@Subscribe @Subscribe
public void onDisabled(EnableEvent e) { public void onDisabled(EnableEvent e) {
@ -94,16 +94,20 @@ public abstract class BasicButton extends Component {
setPressed(false); setPressed(false);
} }
} }
// Trigger virtualClick when button is released // Trigger virtualClick when button is released
@Subscribe @Subscribe
public void onRelease(ButtonEvent.Release e) { public void onRelease(ButtonEvent.Release e) {
virtualClick(); virtualClick();
} }
}); });
} }
public BasicButton(String name, String label, Font labelFont) {
this(name, new Label(name + ".Label", labelFont, label));
}
public BasicButton(String name, String label) { public BasicButton(String name, String label) {
this(name, label, new Font()); this(name, label, new Font());
} }
@ -111,7 +115,7 @@ public abstract class BasicButton extends Component {
public boolean isPressed() { public boolean isPressed() {
return isPressed; return isPressed;
} }
public void click() { public void click() {
setPressed(true); setPressed(true);
setPressed(false); setPressed(false);
@ -120,7 +124,7 @@ public abstract class BasicButton extends Component {
public void setPressed(boolean isPressed) { public void setPressed(boolean isPressed) {
if (this.isPressed != isPressed) { if (this.isPressed != isPressed) {
this.isPressed = isPressed; this.isPressed = isPressed;
if (isPressed) { if (isPressed) {
takeFocus(); takeFocus();
} }
@ -128,16 +132,16 @@ public abstract class BasicButton extends Component {
dispatchEvent(ButtonEvent.create(this, this.isPressed)); dispatchEvent(ButtonEvent.create(this, this.isPressed));
} }
} }
public BasicButton addAction(Consumer<BasicButton> action) { public BasicButton addAction(Consumer<BasicButton> action) {
this.actions.add(Objects.requireNonNull(action, "action")); this.actions.add(Objects.requireNonNull(action, "action"));
return this; return this;
} }
public boolean removeAction(Consumer<BasicButton> action) { public boolean removeAction(Consumer<BasicButton> action) {
return this.actions.remove(action); return this.actions.remove(action);
} }
public void virtualClick() { public void virtualClick() {
this.actions.forEach(action -> { this.actions.forEach(action -> {
action.accept(this); action.accept(this);
@ -147,5 +151,5 @@ public abstract class BasicButton extends Component {
public Label getLabel() { public Label getLabel() {
return label; return label;
} }
} }

View File

@ -28,7 +28,11 @@ public class Button extends BasicButton {
public Button(String name, String label, Font labelFont) { public Button(String name, String label, Font labelFont) {
super(name, label, labelFont); super(name, label, labelFont);
} }
public Button(String name, Label label) {
super(name, label);
}
public Button(String name, String label) { public Button(String name, String label) {
this(name, label, new Font()); this(name, label, new Font());
} }
@ -36,7 +40,7 @@ public class Button extends BasicButton {
@Override @Override
protected void assembleSelf(RenderTarget target) { protected void assembleSelf(RenderTarget target) {
// Border // Border
Vec4 borderColor; Vec4 borderColor;
if (isPressed() || isHovered() || isFocused()) { if (isPressed() || isHovered() || isFocused()) {
borderColor = Colors.BLUE; borderColor = Colors.BLUE;
@ -44,9 +48,9 @@ public class Button extends BasicButton {
borderColor = Colors.LIGHT_GRAY; borderColor = Colors.LIGHT_GRAY;
} }
target.fill(getX(), getY(), getWidth(), getHeight(), borderColor); target.fill(getX(), getY(), getWidth(), getHeight(), borderColor);
// Inside area // Inside area
if (isPressed()) { if (isPressed()) {
// Do nothing // Do nothing
} else { } else {
@ -58,20 +62,20 @@ public class Button extends BasicButton {
} }
target.fill(getX() + 2, getY() + 2, getWidth() - 4, getHeight() - 4, backgroundColor); target.fill(getX() + 2, getY() + 2, getWidth() - 4, getHeight() - 4, backgroundColor);
} }
// Change label font color // Change label font color
if (isPressed()) { if (isPressed()) {
getLabel().setFont(getLabel().getFont().withColor(Colors.WHITE)); getLabel().setFont(getLabel().getFont().withColor(Colors.WHITE));
} else { } else {
getLabel().setFont(getLabel().getFont().withColor(Colors.BLACK)); getLabel().setFont(getLabel().getFont().withColor(Colors.BLACK));
} }
} }
@Override @Override
protected void postAssembleSelf(RenderTarget target) { protected void postAssembleSelf(RenderTarget target) {
// Apply disable tint // Apply disable tint
if (!isEnabled()) { if (!isEnabled()) {
target.fill(getX(), getY(), getWidth(), getHeight(), Colors.toVector(0x88FFFFFF)); target.fill(getX(), getY(), getWidth(), getHeight(), Colors.toVector(0x88FFFFFF));
} }

View File

@ -27,24 +27,24 @@ import ru.windcorp.progressia.client.graphics.gui.layout.LayoutAlign;
import ru.windcorp.progressia.client.graphics.gui.layout.LayoutHorizontal; import ru.windcorp.progressia.client.graphics.gui.layout.LayoutHorizontal;
public class Checkbox extends BasicButton { public class Checkbox extends BasicButton {
private class Tick extends Component { private class Tick extends Component {
public Tick() { public Tick() {
super(Checkbox.this.getName() + ".Tick"); super(Checkbox.this.getName() + ".Tick");
setPreferredSize(new Vec2i(Typefaces.getDefault().getLineHeight() * 3 / 2)); setPreferredSize(new Vec2i(Typefaces.getDefault().getLineHeight() * 3 / 2));
} }
@Override @Override
protected void assembleSelf(RenderTarget target) { protected void assembleSelf(RenderTarget target) {
int size = getPreferredSize().x; int size = getPreferredSize().x;
int x = getX(); int x = getX();
int y = getY() + (getHeight() - size) / 2; int y = getY() + (getHeight() - size) / 2;
// Border // Border
Vec4 borderColor; Vec4 borderColor;
if (Checkbox.this.isPressed() || Checkbox.this.isHovered() || Checkbox.this.isFocused()) { if (Checkbox.this.isPressed() || Checkbox.this.isHovered() || Checkbox.this.isFocused()) {
borderColor = Colors.BLUE; borderColor = Colors.BLUE;
@ -52,9 +52,9 @@ public class Checkbox extends BasicButton {
borderColor = Colors.LIGHT_GRAY; borderColor = Colors.LIGHT_GRAY;
} }
target.fill(x, y, size, size, borderColor); target.fill(x, y, size, size, borderColor);
// Inside area // Inside area
if (Checkbox.this.isPressed()) { if (Checkbox.this.isPressed()) {
// Do nothing // Do nothing
} else { } else {
@ -66,9 +66,9 @@ public class Checkbox extends BasicButton {
} }
target.fill(x + 2, y + 2, size - 4, size - 4, backgroundColor); target.fill(x + 2, y + 2, size - 4, size - 4, backgroundColor);
} }
// "Tick" // "Tick"
if (Checkbox.this.isChecked()) { if (Checkbox.this.isChecked()) {
target.fill(x + 4, y + 4, size - 8, size - 8, Colors.BLUE); target.fill(x + 4, y + 4, size - 8, size - 8, Colors.BLUE);
} }
@ -81,10 +81,10 @@ public class Checkbox extends BasicButton {
public Checkbox(String name, String label, Font labelFont, boolean check) { public Checkbox(String name, String label, Font labelFont, boolean check) {
super(name, label, labelFont); super(name, label, labelFont);
this.checked = check; this.checked = check;
assert getChildren().size() == 1 : "Checkbox expects that BasicButton contains exactly one child"; assert getChildren().size() == 1 : "Checkbox expects that BasicButton contains exactly one child";
Component basicChild = getChild(0); Component basicChild = getChild(0);
Group group = new Group(getName() + ".LabelAndTick", new LayoutHorizontal(0, 10)); Group group = new Group(getName() + ".LabelAndTick", new LayoutHorizontal(0, 10));
removeChild(basicChild); removeChild(basicChild);
setLayout(new LayoutAlign(0, 0.5f, 10)); setLayout(new LayoutAlign(0, 0.5f, 10));
@ -92,18 +92,18 @@ public class Checkbox extends BasicButton {
group.addChild(new Tick()); group.addChild(new Tick());
group.addChild(basicChild); group.addChild(basicChild);
addChild(group); addChild(group);
addAction(b -> switchState()); addAction(b -> switchState());
} }
public Checkbox(String name, String label, Font labelFont) { public Checkbox(String name, String label, Font labelFont) {
this(name, label, labelFont, false); this(name, label, labelFont, false);
} }
public Checkbox(String name, String label, boolean check) { public Checkbox(String name, String label, boolean check) {
this(name, label, new Font(), check); this(name, label, new Font(), check);
} }
public Checkbox(String name, String label) { public Checkbox(String name, String label) {
this(name, label, false); this(name, label, false);
} }
@ -111,14 +111,14 @@ public class Checkbox extends BasicButton {
public void switchState() { public void switchState() {
setChecked(!isChecked()); setChecked(!isChecked());
} }
/** /**
* @return the checked * @return the checked
*/ */
public boolean isChecked() { public boolean isChecked() {
return checked; return checked;
} }
/** /**
* @param checked the checked to set * @param checked the checked to set
*/ */
@ -129,21 +129,21 @@ public class Checkbox extends BasicButton {
@Override @Override
protected void assembleSelf(RenderTarget target) { protected void assembleSelf(RenderTarget target) {
// Change label font color // Change label font color
if (isPressed()) { if (isPressed()) {
getLabel().setFont(getLabel().getFont().withColor(Colors.BLUE)); getLabel().setFont(getLabel().getFont().withColor(Colors.BLUE));
} else { } else {
getLabel().setFont(getLabel().getFont().withColor(Colors.BLACK)); getLabel().setFont(getLabel().getFont().withColor(Colors.BLACK));
} }
} }
@Override @Override
protected void postAssembleSelf(RenderTarget target) { protected void postAssembleSelf(RenderTarget target) {
// Apply disable tint // Apply disable tint
if (!isEnabled()) { if (!isEnabled()) {
target.fill(getX(), getY(), getWidth(), getHeight(), Colors.toVector(0x88FFFFFF)); target.fill(getX(), getY(), getWidth(), getHeight(), Colors.toVector(0x88FFFFFF));
} }
} }
} }

View File

@ -30,30 +30,30 @@ import ru.windcorp.progressia.client.graphics.gui.layout.LayoutHorizontal;
import ru.windcorp.progressia.client.graphics.input.KeyEvent; import ru.windcorp.progressia.client.graphics.input.KeyEvent;
public class RadioButton extends BasicButton { public class RadioButton extends BasicButton {
private class Tick extends Component { private class Tick extends Component {
public Tick() { public Tick() {
super(RadioButton.this.getName() + ".Tick"); super(RadioButton.this.getName() + ".Tick");
setPreferredSize(new Vec2i(Typefaces.getDefault().getLineHeight() * 3 / 2)); setPreferredSize(new Vec2i(Typefaces.getDefault().getLineHeight() * 3 / 2));
} }
private void cross(RenderTarget target, int x, int y, int size, Vec4 color) { private void cross(RenderTarget target, int x, int y, int size, Vec4 color) {
target.fill(x + 4, y, size - 8, size, color); target.fill(x + 4, y, size - 8, size, color);
target.fill(x + 2, y + 2, size - 4, size - 4, color); target.fill(x + 2, y + 2, size - 4, size - 4, color);
target.fill(x, y + 4, size, size - 8, color); target.fill(x, y + 4, size, size - 8, color);
} }
@Override @Override
protected void assembleSelf(RenderTarget target) { protected void assembleSelf(RenderTarget target) {
int size = getPreferredSize().x; int size = getPreferredSize().x;
int x = getX(); int x = getX();
int y = getY() + (getHeight() - size) / 2; int y = getY() + (getHeight() - size) / 2;
// Border // Border
Vec4 borderColor; Vec4 borderColor;
if (RadioButton.this.isPressed() || RadioButton.this.isHovered() || RadioButton.this.isFocused()) { if (RadioButton.this.isPressed() || RadioButton.this.isHovered() || RadioButton.this.isFocused()) {
borderColor = Colors.BLUE; borderColor = Colors.BLUE;
@ -61,9 +61,9 @@ public class RadioButton extends BasicButton {
borderColor = Colors.LIGHT_GRAY; borderColor = Colors.LIGHT_GRAY;
} }
cross(target, x, y, size, borderColor); cross(target, x, y, size, borderColor);
// Inside area // Inside area
if (RadioButton.this.isPressed()) { if (RadioButton.this.isPressed()) {
// Do nothing // Do nothing
} else { } else {
@ -75,9 +75,9 @@ public class RadioButton extends BasicButton {
} }
cross(target, x + 2, y + 2, size - 4, backgroundColor); cross(target, x + 2, y + 2, size - 4, backgroundColor);
} }
// "Tick" // "Tick"
if (RadioButton.this.isChecked()) { if (RadioButton.this.isChecked()) {
cross(target, x + 4, y + 4, size - 8, Colors.BLUE); cross(target, x + 4, y + 4, size - 8, Colors.BLUE);
} }
@ -86,16 +86,16 @@ public class RadioButton extends BasicButton {
} }
private boolean checked; private boolean checked;
private RadioButtonGroup group = null; private RadioButtonGroup group = null;
public RadioButton(String name, String label, Font labelFont, boolean check) { public RadioButton(String name, String label, Font labelFont, boolean check) {
super(name, label, labelFont); super(name, label, labelFont);
this.checked = check; this.checked = check;
assert getChildren().size() == 1 : "RadioButton expects that BasicButton contains exactly one child"; assert getChildren().size() == 1 : "RadioButton expects that BasicButton contains exactly one child";
Component basicChild = getChild(0); Component basicChild = getChild(0);
Group group = new Group(getName() + ".LabelAndTick", new LayoutHorizontal(0, 10)); Group group = new Group(getName() + ".LabelAndTick", new LayoutHorizontal(0, 10));
removeChild(basicChild); removeChild(basicChild);
setLayout(new LayoutAlign(0, 0.5f, 10)); setLayout(new LayoutAlign(0, 0.5f, 10));
@ -103,16 +103,17 @@ public class RadioButton extends BasicButton {
group.addChild(new Tick()); group.addChild(new Tick());
group.addChild(basicChild); group.addChild(basicChild);
addChild(group); addChild(group);
addListener(KeyEvent.class, e -> { addListener(KeyEvent.class, e -> {
if (e.isRelease()) return false; if (e.isRelease())
return false;
if (e.getKey() == GLFW.GLFW_KEY_LEFT || e.getKey() == GLFW.GLFW_KEY_UP) { if (e.getKey() == GLFW.GLFW_KEY_LEFT || e.getKey() == GLFW.GLFW_KEY_UP) {
if (this.group != null) { if (this.group != null) {
this.group.selectPrevious(); this.group.selectPrevious();
this.group.getSelected().takeFocus(); this.group.getSelected().takeFocus();
} }
return true; return true;
} else if (e.getKey() == GLFW.GLFW_KEY_RIGHT || e.getKey() == GLFW.GLFW_KEY_DOWN) { } else if (e.getKey() == GLFW.GLFW_KEY_RIGHT || e.getKey() == GLFW.GLFW_KEY_DOWN) {
if (this.group != null) { if (this.group != null) {
@ -121,85 +122,87 @@ public class RadioButton extends BasicButton {
} }
return true; return true;
} }
return false; return false;
}); });
addAction(b -> setChecked(true)); addAction(b -> setChecked(true));
} }
public RadioButton(String name, String label, Font labelFont) { public RadioButton(String name, String label, Font labelFont) {
this(name, label, labelFont, false); this(name, label, labelFont, false);
} }
public RadioButton(String name, String label, boolean check) { public RadioButton(String name, String label, boolean check) {
this(name, label, new Font(), check); this(name, label, new Font(), check);
} }
public RadioButton(String name, String label) { public RadioButton(String name, String label) {
this(name, label, false); this(name, label, false);
} }
/** /**
* @param group the group to set * @param group the group to set
*/ */
public RadioButton setGroup(RadioButtonGroup group) { public RadioButton setGroup(RadioButtonGroup group) {
if (this.group != null) { if (this.group != null) {
group.selectNext(); group.selectNext();
removeAction(group.listener); removeAction(group.listener);
group.buttons.remove(this); group.buttons.remove(this);
group.getSelected(); // Clear reference if this was the only button in the group group.getSelected(); // Clear reference if this was the only button
// in the group
} }
this.group = group; this.group = group;
if (this.group != null) { if (this.group != null) {
group.buttons.add(this); group.buttons.add(this);
addAction(group.listener); addAction(group.listener);
} }
setChecked(false); setChecked(false);
return this; return this;
} }
/** /**
* @return the checked * @return the checked
*/ */
public boolean isChecked() { public boolean isChecked() {
return checked; return checked;
} }
/** /**
* @param checked the checked to set * @param checked the checked to set
*/ */
public void setChecked(boolean checked) { public void setChecked(boolean checked) {
this.checked = checked; this.checked = checked;
if (group != null) { if (group != null) {
group.listener.accept(this); // Failsafe for manual invocations of setChecked() group.listener.accept(this); // Failsafe for manual invocations of
// setChecked()
} }
} }
@Override @Override
protected void assembleSelf(RenderTarget target) { protected void assembleSelf(RenderTarget target) {
// Change label font color // Change label font color
if (isPressed()) { if (isPressed()) {
getLabel().setFont(getLabel().getFont().withColor(Colors.BLUE)); getLabel().setFont(getLabel().getFont().withColor(Colors.BLUE));
} else { } else {
getLabel().setFont(getLabel().getFont().withColor(Colors.BLACK)); getLabel().setFont(getLabel().getFont().withColor(Colors.BLACK));
} }
} }
@Override @Override
protected void postAssembleSelf(RenderTarget target) { protected void postAssembleSelf(RenderTarget target) {
// Apply disable tint // Apply disable tint
if (!isEnabled()) { if (!isEnabled()) {
target.fill(getX(), getY(), getWidth(), getHeight(), Colors.toVector(0x88FFFFFF)); target.fill(getX(), getY(), getWidth(), getHeight(), Colors.toVector(0x88FFFFFF));
} }
} }
} }

View File

@ -0,0 +1,35 @@
package ru.windcorp.progressia.common.util;
import glm.vec._3.i.Vec3i;
public class HashableVec3i {
public Vec3i value;
public HashableVec3i(Vec3i inValue)
{
value = inValue;
}
@Override
public int hashCode() // Uses first 3 primes greater than 2**30
{
return 1073741827 * value.x + 1073741831 * value.y + 1073741833 * value.z;
}
@Override
public boolean equals(Object comparee)
{
if (comparee == null)
{
return false;
}
if (comparee.getClass() != HashableVec3i.class)
{
return false;
}
HashableVec3i compareeCast = (HashableVec3i) comparee;
return compareeCast.value == value;
}
}

View File

@ -27,6 +27,7 @@ import ru.windcorp.progressia.common.util.crash.CrashReports;
import ru.windcorp.progressia.common.world.entity.EntityData; import ru.windcorp.progressia.common.world.entity.EntityData;
import ru.windcorp.progressia.common.world.entity.EntityDataRegistry; import ru.windcorp.progressia.common.world.entity.EntityDataRegistry;
import ru.windcorp.progressia.server.events.PlayerJoinedEvent; import ru.windcorp.progressia.server.events.PlayerJoinedEvent;
import ru.windcorp.progressia.server.events.PlayerLeftEvent;
import ru.windcorp.progressia.test.TestContent; import ru.windcorp.progressia.test.TestContent;
public class PlayerManager { public class PlayerManager {
@ -47,6 +48,11 @@ public class PlayerManager {
this.players.add(player); this.players.add(player);
getServer().postEvent(new PlayerJoinedEvent.Immutable(getServer(), player)); getServer().postEvent(new PlayerJoinedEvent.Immutable(getServer(), player));
} }
public void removePlayer(Player player) {
this.players.remove(player);
getServer().postEvent(new PlayerLeftEvent.Immutable(getServer(), player));
}
public EntityData conjurePlayerEntity(String login) { public EntityData conjurePlayerEntity(String login) {
// TODO Live up to the name // TODO Live up to the name

View File

@ -15,7 +15,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package ru.windcorp.progressia.server; package ru.windcorp.progressia.server;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
@ -26,10 +26,13 @@ import org.apache.logging.log4j.LogManager;
import ru.windcorp.progressia.common.util.crash.CrashReports; import ru.windcorp.progressia.common.util.crash.CrashReports;
import ru.windcorp.progressia.server.world.ticking.TickerCoordinator; import ru.windcorp.progressia.server.world.ticking.TickerCoordinator;
@SuppressWarnings("unused")
public class ServerThread implements Runnable { public class ServerThread implements Runnable {
private static final ThreadLocal<Server> SERVER_THREADS_MAP = new ThreadLocal<>(); private static final ThreadLocal<Server> SERVER_THREADS_MAP = new ThreadLocal<>();
private static boolean isShuttingDown;
public static Server getCurrentServer() { public static Server getCurrentServer() {
return SERVER_THREADS_MAP.get(); return SERVER_THREADS_MAP.get();
} }
@ -63,6 +66,7 @@ public class ServerThread implements Runnable {
} }
public void start() { public void start() {
isShuttingDown = false;
ticker.start(); ticker.start();
executor.scheduleAtFixedRate(this, 0, 1000 / 20, TimeUnit.MILLISECONDS); executor.scheduleAtFixedRate(this, 0, 1000 / 20, TimeUnit.MILLISECONDS);
} }
@ -70,6 +74,11 @@ public class ServerThread implements Runnable {
@Override @Override
public void run() { public void run() {
try { try {
if (isShuttingDown) {
getTicker().stop();
executor.shutdown();
return;
}
server.tick(); server.tick();
ticker.runOneTick(); ticker.runOneTick();
} catch (Throwable e) { } catch (Throwable e) {
@ -78,13 +87,10 @@ public class ServerThread implements Runnable {
} }
public void stop() { public void stop() {
try {
executor.awaitTermination(10, TimeUnit.MINUTES);
} catch (InterruptedException e) {
LogManager.getLogger().warn("Received interrupt in ServerThread.stop(), aborting wait");
}
getTicker().stop(); isShuttingDown = true;
// getTicker().stop();
} }
public Server getServer() { public Server getServer() {

View File

@ -92,6 +92,9 @@ public class ClientManager {
public void disconnectClient(Client client) { public void disconnectClient(Client client) {
client.disconnect(); client.disconnect();
clientsById.remove(client.getId()); clientsById.remove(client.getId());
if (client instanceof ClientPlayer) {
getServer().getPlayerManager().removePlayer(((ClientPlayer) client).getPlayer());
}
} }
public void processPackets() { public void processPackets() {

View File

@ -17,7 +17,11 @@
*/ */
package ru.windcorp.progressia.test; package ru.windcorp.progressia.test;
import java.util.Collection;
import ru.windcorp.progressia.client.ClientState;
import ru.windcorp.progressia.client.graphics.Colors; import ru.windcorp.progressia.client.graphics.Colors;
import ru.windcorp.progressia.client.graphics.GUI;
import ru.windcorp.progressia.client.graphics.font.Font; import ru.windcorp.progressia.client.graphics.font.Font;
import ru.windcorp.progressia.client.graphics.gui.Button; import ru.windcorp.progressia.client.graphics.gui.Button;
import ru.windcorp.progressia.client.graphics.gui.Checkbox; import ru.windcorp.progressia.client.graphics.gui.Checkbox;
@ -25,45 +29,71 @@ import ru.windcorp.progressia.client.graphics.gui.Label;
import ru.windcorp.progressia.client.graphics.gui.RadioButton; import ru.windcorp.progressia.client.graphics.gui.RadioButton;
import ru.windcorp.progressia.client.graphics.gui.RadioButtonGroup; import ru.windcorp.progressia.client.graphics.gui.RadioButtonGroup;
import ru.windcorp.progressia.client.graphics.gui.menu.MenuLayer; import ru.windcorp.progressia.client.graphics.gui.menu.MenuLayer;
import ru.windcorp.progressia.client.localization.MutableStringLocalized;
import ru.windcorp.progressia.server.Player;
import ru.windcorp.progressia.server.Server;
import ru.windcorp.progressia.server.ServerState;
public class LayerButtonTest extends MenuLayer { public class LayerButtonTest extends MenuLayer {
boolean alive = true;
public LayerButtonTest() { public LayerButtonTest() {
super("ButtonTest"); super("ButtonTest");
addTitle(); addTitle();
Button blockableButton; Button blockableButton;
getContent().addChild((blockableButton = new Button("BlockableButton", "Blockable")).addAction(b -> { getContent().addChild((blockableButton = new Button("BlockableButton", "Blockable")).addAction(b -> {
System.out.println("Button Blockable!"); System.out.println("Button Blockable!");
})); }));
blockableButton.setEnabled(false); blockableButton.setEnabled(false);
getContent().addChild(new Checkbox("EnableButton", "Enable").addAction(b -> { getContent().addChild(new Checkbox("EnableButton", "Enable").addAction(b -> {
blockableButton.setEnabled(((Checkbox) b).isChecked()); blockableButton.setEnabled(((Checkbox) b).isChecked());
})); }));
RadioButtonGroup group = new RadioButtonGroup().addAction(g -> { RadioButtonGroup group = new RadioButtonGroup().addAction(g -> {
System.out.println("RBG! " + g.getSelected().getLabel().getCurrentText()); System.out.println("RBG! " + g.getSelected().getLabel().getCurrentText());
}); });
getContent().addChild(new RadioButton("RB1", "Moon").setGroup(group)); getContent().addChild(new RadioButton("RB1", "Moon").setGroup(group));
getContent().addChild(new RadioButton("RB2", "Type").setGroup(group)); getContent().addChild(new RadioButton("RB2", "Type").setGroup(group));
getContent().addChild(new RadioButton("RB3", "Ice").setGroup(group)); getContent().addChild(new RadioButton("RB3", "Ice").setGroup(group));
getContent().addChild(new RadioButton("RB4", "Cream").setGroup(group)); getContent().addChild(new RadioButton("RB4", "Cream").setGroup(group));
getContent().getChild(getContent().getChildren().size() - 1).setEnabled(false); getContent().getChild(getContent().getChildren().size() - 1).setEnabled(false);
getContent().addChild(new Label("Hint", new Font().withColor(Colors.LIGHT_GRAY), "This is a MenuLayer")); getContent().addChild(new Label("Hint", new Font().withColor(Colors.LIGHT_GRAY), "This is a MenuLayer"));
getContent().addChild(new Button("Continue", "Continue").addAction(b -> { getContent().addChild(new Button("Continue", "Continue").addAction(b -> {
getCloseAction().run(); getCloseAction().run();
})); }));
getContent().addChild(new Button("Quit", "Quit").addAction(b -> { getContent().addChild(new Button("Menu", "Back To Menu").addAction(b -> {
System.exit(0); getCloseAction().run();
Collection<Player> players = ServerState.getInstance().getPlayerManager().getPlayers();
players.clear();
ClientState.disconnectFromLocalServer();
GUI.addTopLayer(new LayerTestText("Text", new MutableStringLocalized("LayerText.Save"), layer -> {
Server server = ServerState.getInstance();
if (server != null && server.getWorld().getChunks().isEmpty()) {
GUI.removeLayer(layer);
// TODO Refactor, this shouldn't be here
GUI.addTopLayer(new LayerTitle("Title"));
ServerState.getInstance().shutdown("Safe Exit");
ServerState.setInstance(null);
TestPlayerControls.resetInstance();
}
}));
ClientState.setInstance(null);
})); }));
getContent().takeFocus(); getContent().takeFocus();
} }

View File

@ -0,0 +1,29 @@
package ru.windcorp.progressia.test;
import java.util.function.Consumer;
import ru.windcorp.progressia.client.graphics.Colors;
import ru.windcorp.progressia.client.graphics.font.Font;
import ru.windcorp.progressia.client.graphics.gui.GUILayer;
import ru.windcorp.progressia.client.graphics.gui.Label;
import ru.windcorp.progressia.client.graphics.gui.layout.LayoutAlign;
import ru.windcorp.progressia.client.localization.MutableString;
public class LayerTestText extends GUILayer {
private final Consumer<LayerTestText> remover;
public LayerTestText(String name, MutableString value, Consumer<LayerTestText> remover) {
super(name, new LayoutAlign(15));
this.remover = remover;
Font titleFont = new Font().deriveBold().withColor(Colors.BLACK).withAlign(0.5f);
getRoot().addChild(new Label(name + ".Text", titleFont, value));
}
@Override
protected void doRender() {
super.doRender();
remover.accept(this);
}
}

View File

@ -0,0 +1,37 @@
package ru.windcorp.progressia.test;
import ru.windcorp.progressia.ProgressiaLauncher;
import ru.windcorp.progressia.client.graphics.Colors;
import ru.windcorp.progressia.client.graphics.GUI;
import ru.windcorp.progressia.client.graphics.font.Font;
import ru.windcorp.progressia.client.graphics.gui.Button;
import ru.windcorp.progressia.client.graphics.gui.GUILayer;
import ru.windcorp.progressia.client.graphics.gui.Label;
import ru.windcorp.progressia.client.graphics.gui.layout.LayoutVertical;
import ru.windcorp.progressia.client.localization.MutableString;
import ru.windcorp.progressia.client.localization.MutableStringLocalized;
public class LayerTitle extends GUILayer {
public LayerTitle(String name) {
super(name, new LayoutVertical(20, 10));
MutableString title = new MutableStringLocalized("Layer" + name + ".Title");
Font titleFont = new Font().deriveBold().withColor(Colors.BLACK).withAlign(0.5f);
getRoot().addChild(new Label(name + ".Title", titleFont, title));
Font buttonFont = titleFont;
MutableString playText = new MutableStringLocalized("Layer" + name + ".Play");
getRoot().addChild(new Button(name + ".Play", new Label(name + ".Play", buttonFont, playText)).addAction(b -> {
GUI.removeLayer(this);
ProgressiaLauncher.play();
}));
MutableString quitText = new MutableStringLocalized("Layer" + name + ".Quit");
getRoot().addChild(new Button(name + "Quit", new Label(name + ".Quit", buttonFont, quitText)).addAction(b -> {
System.exit(0);
}));
}
}

View File

@ -46,10 +46,10 @@ import ru.windcorp.progressia.server.ServerState;
public class TestPlayerControls { public class TestPlayerControls {
private static final TestPlayerControls INSTANCE = new TestPlayerControls(); private static TestPlayerControls instance = new TestPlayerControls();
public static TestPlayerControls getInstance() { public static TestPlayerControls getInstance() {
return INSTANCE; return instance;
} }
private static final double MODE_SWITCH_MAX_DELAY = 300 * Units.MILLISECONDS; private static final double MODE_SWITCH_MAX_DELAY = 300 * Units.MILLISECONDS;
@ -90,6 +90,10 @@ public class TestPlayerControls {
private LayerTestGUI debugLayer = null; private LayerTestGUI debugLayer = null;
private Runnable updateCallback = null; private Runnable updateCallback = null;
public static void resetInstance() {
instance = new TestPlayerControls();
}
public void applyPlayerControls() { public void applyPlayerControls() {
if (ClientState.getInstance() == null || !ClientState.getInstance().isReady()) { if (ClientState.getInstance() == null || !ClientState.getInstance().isReady()) {

View File

@ -15,17 +15,30 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
package ru.windcorp.progressia.test; package ru.windcorp.progressia.test;
import java.io.BufferedInputStream; import java.io.BufferedInputStream;
import java.io.BufferedOutputStream; import java.io.BufferedOutputStream;
import java.io.BufferedWriter;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream; import java.io.DataInputStream;
import java.io.DataOutputStream; import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException; import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Scanner;
import java.util.zip.DeflaterOutputStream; import java.util.zip.DeflaterOutputStream;
import java.util.zip.InflaterInputStream; import java.util.zip.InflaterInputStream;
@ -34,6 +47,7 @@ import org.apache.logging.log4j.Logger;
import glm.vec._3.i.Vec3i; import glm.vec._3.i.Vec3i;
import ru.windcorp.progressia.common.state.IOContext; import ru.windcorp.progressia.common.state.IOContext;
import ru.windcorp.progressia.common.util.HashableVec3i;
import ru.windcorp.progressia.common.world.DefaultChunkData; import ru.windcorp.progressia.common.world.DefaultChunkData;
import ru.windcorp.progressia.common.world.DecodingException; import ru.windcorp.progressia.common.world.DecodingException;
import ru.windcorp.progressia.common.world.DefaultWorldData; import ru.windcorp.progressia.common.world.DefaultWorldData;
@ -42,47 +56,342 @@ import ru.windcorp.progressia.server.Server;
public class TestWorldDiskIO { public class TestWorldDiskIO {
private static final Path SAVE_DIR = Paths.get("tmp_world"); private static Path SAVE_DIR = Paths.get("tmp_world");
private static final String formatFile = "world.format";
private static final Logger LOG = LogManager.getLogger("TestWorldDiskIO"); private static final Logger LOG = LogManager.getLogger("TestWorldDiskIO");
private static HashMap<HashableVec3i, MappedByteBuffer> mappedByteMap;
private static final boolean ENABLE = true;
private static final boolean ENABLE = false; private static int maxSize = 1048576;
private static int sectorSize = maxSize / 256;
private static final int bestFormat = 65536;
// private Map<Vec3i,Vec3i> regions = new HashMap<Vec3i,Vec3i>();
private static Vec3i regionSize;
private static int chunksPerRegion;
private static int offsetBytes;
private static int currentFormat = -1;
private static String extension = ".null";
private static int natFromInt(int loc) {
if (loc < 0)
return -2*loc - 1;
return 2*loc;
}
/*
* private static int intFromNat(int loc) // Possibly unused
* {
* if ((loc & 1) == 1)
* return -loc >> 1;
* return loc >> 1;
* }
*/
private static Vec3i getRegion(Vec3i chunkLoc) {
int x = chunkLoc.x;
if (x<0)
{
x /= regionSize.x;
x--;
}
else
{
x /= regionSize.x;
}
int y = chunkLoc.y;
if (y<0)
{
y /= regionSize.y;
y--;
}
else
{
y /= regionSize.y;
}
int z = chunkLoc.z;
if (z<0)
{
z /= regionSize.z;
z--;
}
else
{
z /= regionSize.z;
}
return new Vec3i(
natFromInt(x),
natFromInt(y),
natFromInt(z)
);
}
private static int mod(int a, int m) {
return ((a % m) + m) % m;
}
private static Vec3i getRegionLoc(Vec3i chunkLoc) {
return new Vec3i(mod(chunkLoc.x, regionSize.x), mod(chunkLoc.y, regionSize.y), mod(chunkLoc.z, regionSize.z));
}
public static void initRegions() {
initRegions(null);
}
public static void initRegions(Path worldPath) {
if (worldPath != null) {
SAVE_DIR = worldPath;
}
// regions.put(new Vec3i(0,0,0), new Vec3i(1,1,1));
}
public static int getAvailableSector(MappedByteBuffer mbb)
{
int sectorsUsed = 0;
for (int i=offsetBytes; i<(offsetBytes+1)*chunksPerRegion; i+= (offsetBytes+1))
{
sectorsUsed += mbb.get(i);
}
return sectorsUsed;
}
private static void setRegionSize(int format) {
mappedByteMap = new HashMap<HashableVec3i, MappedByteBuffer>();
switch (format) {
case 0:
case 1:
regionSize = new Vec3i(1);
chunksPerRegion = 1;
currentFormat = format;
extension = ".progressia_chunk";
break;
case 65536:
regionSize = new Vec3i(16);
chunksPerRegion = 16 * 16 * 16;
currentFormat = 65536;
offsetBytes = 3;
extension = ".progressia_region";
break;
}
}
/*private static void expand(int sectors) {
}*/
public static void saveChunk(DefaultChunkData chunk, Server server) { public static void saveChunk(DefaultChunkData chunk, Server server) {
if (!ENABLE) if (!ENABLE)
return; return;
try { try {
LOG.debug(
"Saving {} {} {}",
chunk.getPosition().x,
chunk.getPosition().y,
chunk.getPosition().z
);
Files.createDirectories(SAVE_DIR); if (currentFormat == 0) {
LOG.debug(
Path path = SAVE_DIR.resolve( "Saving {} {} {}",
String.format(
"chunk_%+d_%+d_%+d.progressia_chunk",
chunk.getPosition().x, chunk.getPosition().x,
chunk.getPosition().y, chunk.getPosition().y,
chunk.getPosition().z chunk.getPosition().z
) );
);
Files.createDirectories(SAVE_DIR);
Path path = SAVE_DIR.resolve(
String.format(
"chunk_%+d_%+d_%+d" + extension,
chunk.getPosition().x,
chunk.getPosition().y,
chunk.getPosition().z
)
);
try (
DataOutputStream output = new DataOutputStream(
new DeflaterOutputStream(new BufferedOutputStream(Files.newOutputStream(path)))
)
) {
ChunkIO.save(chunk, output, IOContext.SAVE);
writeGenerationHint(chunk, output, server);
}
} else if (currentFormat == 1) {
LOG.debug(
"Saving {} {} {}",
chunk.getPosition().x,
chunk.getPosition().y,
chunk.getPosition().z
);
Files.createDirectories(SAVE_DIR);
Vec3i saveCoords = getRegion(chunk.getPosition());
Path path = SAVE_DIR.resolve(
String.format(
"chunk_%d_%d_%d" + extension,
saveCoords.x,
saveCoords.y,
saveCoords.z
)
);
try (
DataOutputStream output = new DataOutputStream(
new DeflaterOutputStream(new BufferedOutputStream(Files.newOutputStream(path)))
)
) {
ChunkIO.save(chunk, output, IOContext.SAVE);
writeGenerationHint(chunk, output, server);
}
} else if (currentFormat == 65536) {
LOG.debug(
"Saving {} {} {}",
chunk.getPosition().x,
chunk.getPosition().y,
chunk.getPosition().z
);
Files.createDirectories(SAVE_DIR);
Vec3i saveCoords = getRegion(chunk.getPosition());
Path path = SAVE_DIR.resolve(
String.format(
"%d_%d_%d" + extension,
saveCoords.x,
saveCoords.y,
saveCoords.z
)
);
/*
* if (!dosave)
* {
* return;
* }
* dosave = false;
*/
MappedByteBuffer output = mappedByteMap.get(new HashableVec3i(saveCoords));
LOG.info("saveCoords {},{},{}", saveCoords.x, saveCoords.y, saveCoords.z);
if (output == null)
{
output = makeNew(path, new HashableVec3i(saveCoords));
}
// LOG.debug(output.read());
if (output.get() < 0) {
LOG.info("Making header");
ByteBuffer headerBytes = ByteBuffer.allocate((offsetBytes + 1) * chunksPerRegion);
for (int i=0;i<(offsetBytes + 1) * chunksPerRegion;i++)
{
headerBytes.put(i, (byte) 0);
}
output.put(headerBytes);
}
Vec3i pos = getRegionLoc(chunk.getPosition());
int shortOffset = (offsetBytes + 1) * (pos.z + regionSize.z * (pos.y + regionSize.y * pos.x));
int fullOffset = (offsetBytes + 1) * (chunksPerRegion);
output.position(shortOffset);
int offset = 0;
for (int i = 0; i < offsetBytes; i++) {
offset *= 256;
offset += output.get();
}
ByteBuffer readOffset = ByteBuffer.allocate(offsetBytes);
int sectorLength = output.get();
if (sectorLength == 0) {
//int outputLen = (int) output.size();
//offset = (int) (outputLen - fullOffset) / sectorSize + 1;
offset = getAvailableSector(output);
output.position(shortOffset);
//readInt.putInt(offset<<8);
for (int i=0;i<offsetBytes;i++)
{
readOffset.put(offsetBytes-i-1, (byte) (offset<<8));
}
output.put(readOffset);
/*output.position(outputLen);
while (output.size()<fullOffset+sectorSize*offset)
{
output.write(ByteBuffer.wrap( new byte[]{0} ));
}*/
//output.setLength(fullOffset + offset * sectorSize);
// output.write(200);
}
// int bytestoWrite = output.readInt();
// output.mark(sectorSize*sectorLength);
// BufferedOutputStream counter = new
// BufferedOutputStream(Files.newOutputStream(
// SAVE_DIR.resolve(tempFile)));
ByteArrayOutputStream tempDataStream = new ByteArrayOutputStream();
DataOutputStream trueOutput = new DataOutputStream(
new DeflaterOutputStream(
new BufferedOutputStream(tempDataStream)
)
);
// CountingOutputStream countOutput = new
// CountingOutputStream(trueOutput);
// LOG.info("Before: {}",output.);
// trueOutput.writeBytes("uh try this");
// counter.
ChunkIO.save(chunk, trueOutput, IOContext.SAVE);
writeGenerationHint(chunk, trueOutput, server);
/*
* while (counter.getCount()%sectorSize != 0) {
* counter.write(0);
* }
*/
// LOG.info("Wrote {} bytes to
// {},{},{}",trueOutput.size(),chunk.getPosition().x,chunk.getPosition().y,chunk.getPosition().z);
trueOutput.close();
byte tempData[] = tempDataStream.toByteArray();
output.position( fullOffset + sectorSize * offset);
output.put(ByteBuffer.wrap( tempData));
output.position(shortOffset + offsetBytes);
output.put(ByteBuffer.wrap( new byte[] {(byte) (tempData.length / sectorSize + 1)}));
// LOG.info("Used {} sectors",(int)
// tempData.length/sectorSize + 1);
try (
DataOutputStream output = new DataOutputStream(
new DeflaterOutputStream(new BufferedOutputStream(Files.newOutputStream(path)))
)
) {
ChunkIO.save(chunk, output, IOContext.SAVE);
writeGenerationHint(chunk, output, server);
} }
// else if (currentFormat)
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
} }
} }
private static MappedByteBuffer makeNew(Path path, Object hashObj) {
try
{
RandomAccessFile raf = new RandomAccessFile(path.toFile(), "rw");
FileChannel fc = raf.getChannel();
MappedByteBuffer output = fc.map(FileChannel.MapMode.READ_WRITE, 0, maxSize*chunksPerRegion);
output.limit(maxSize*chunksPerRegion);
mappedByteMap.put((HashableVec3i) hashObj, output);
return output;
}
catch (IOException e)
{
LOG.warn("bad things");
}
return null;
}
private static void writeGenerationHint(DefaultChunkData chunk, DataOutputStream output, Server server) private static void writeGenerationHint(DefaultChunkData chunk, DataOutputStream output, Server server)
throws IOException { throws IOException {
server.getWorld().getGenerator().writeGenerationHint(output, chunk.getGenerationHint()); server.getWorld().getGenerator().writeGenerationHint(output, chunk.getGenerationHint());
@ -92,47 +401,197 @@ public class TestWorldDiskIO {
if (!ENABLE) if (!ENABLE)
return null; return null;
Path path = SAVE_DIR.resolve( if (currentFormat == -1) {
String.format( Path formatPath = SAVE_DIR.resolve(formatFile);
"chunk_%+d_%+d_%+d.progressia_chunk", File format = formatPath.toFile();
chunkPos.x,
chunkPos.y,
chunkPos.z
)
);
if (!Files.exists(path)) { if (format.exists()) {
LOG.debug( String data = null;
"Not found {} {} {}", try {
chunkPos.x, Scanner reader = new Scanner(format);
chunkPos.y,
chunkPos.z
);
return null; data = reader.next();
reader.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
byte[] formatBytes = data.getBytes();
int formatNum = formatBytes[0] * 256 * 256 * 256 + formatBytes[1] * 256 * 256 + formatBytes[2] * 256
+ formatBytes[3];
setRegionSize(formatNum);
} else {
setRegionSize(bestFormat);
LOG.debug("Making new world with format {}", bestFormat);
BufferedWriter bw;
try {
bw = new BufferedWriter(new FileWriter(format));
int bfClone = bestFormat;
for (int i = 0; i < 4; i++) {
bw.write(bfClone >> 24);
LOG.debug(bfClone >> 24);
bfClone = bfClone << 8;
}
/*
* bw.write(
* new char[] {
* (char) bestFormat / (256 * 256 * 256),
* (char) (bestFormat % 256) / (256 * 256),
* (char) (bestFormat % (256 * 256)) / (256),
* (char) (bestFormat % (256 * 256 * 256)) }
* );
*/
bw.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
} }
try { if (currentFormat == 0) {
DefaultChunkData result = load(path, chunkPos, world, server);
LOG.debug( Path path = SAVE_DIR.resolve(
"Loaded {} {} {}", String.format(
chunkPos.x, "chunk_%+d_%+d_%+d" + extension,
chunkPos.y, chunkPos.x,
chunkPos.z chunkPos.y,
chunkPos.z
)
); );
return result; if (!Files.exists(path)) {
} catch (Exception e) { LOG.debug(
e.printStackTrace(); "Not found {} {} {}",
LOG.debug( chunkPos.x,
"Could not load {} {} {}", chunkPos.y,
chunkPos.x, chunkPos.z
chunkPos.y, );
chunkPos.z
return null;
}
try {
DefaultChunkData result = load(path, chunkPos, world, server);
LOG.debug(
"Loaded {} {} {}",
chunkPos.x,
chunkPos.y,
chunkPos.z
);
return result;
} catch (Exception e) {
e.printStackTrace();
LOG.debug(
"Could not load {} {} {}",
chunkPos.x,
chunkPos.y,
chunkPos.z
);
return null;
}
} else if (currentFormat == 1) {
Vec3i saveCoords = getRegion(chunkPos);
Path path = SAVE_DIR.resolve(
String.format(
"chunk_%d_%d_%d" + extension,
saveCoords.x,
saveCoords.y,
saveCoords.z
)
); );
return null;
if (!Files.exists(path)) {
LOG.debug(
"Not found {} {} {}",
chunkPos.x,
chunkPos.y,
chunkPos.z
);
return null;
}
try {
DefaultChunkData result = load(path, chunkPos, world, server);
LOG.debug(
"Loaded {} {} {}",
chunkPos.x,
chunkPos.y,
chunkPos.z
);
return result;
} catch (Exception e) {
e.printStackTrace();
LOG.debug(
"Could not load {} {} {}",
chunkPos.x,
chunkPos.y,
chunkPos.z
);
return null;
}
} else if (currentFormat == 65536) {
Vec3i saveCoords = getRegion(chunkPos);
Path path = SAVE_DIR.resolve(
String.format(
"%d_%d_%d" + extension,
saveCoords.x,
saveCoords.y,
saveCoords.z
)
);
if (!Files.exists(path)) {
LOG.debug(
"Not found {} {} {}",
chunkPos.x,
chunkPos.y,
chunkPos.z
);
return null;
}
try {
DefaultChunkData result = loadRegion(path, chunkPos, world, server);
LOG.debug(
"Loaded {} {} {}",
chunkPos.x,
chunkPos.y,
chunkPos.z
);
return result;
} catch (Exception e) {
e.printStackTrace();
LOG.debug(
"Could not load {} {} {}",
chunkPos.x,
chunkPos.y,
chunkPos.z
);
return null;
}
} }
return null;
} }
private static DefaultChunkData load(Path path, Vec3i chunkPos, DefaultWorldData world, Server server) private static DefaultChunkData load(Path path, Vec3i chunkPos, DefaultWorldData world, Server server)
@ -149,6 +608,56 @@ public class TestWorldDiskIO {
} }
} }
private static DefaultChunkData loadRegion(Path path, Vec3i chunkPos, DefaultWorldData world, Server server)
throws IOException,
DecodingException {
try
{
Vec3i streamCoords = getRegion(chunkPos);
MappedByteBuffer input = mappedByteMap.get(new HashableVec3i(streamCoords));
LOG.info("streamCoords {},{},{}", streamCoords.x,streamCoords.y,streamCoords.z);
if (input == null)
{
//input = new RandomAccessFile(path.toFile(), "rw");
//input = Files.newByteChannel(path);
input = makeNew(path, new HashableVec3i(streamCoords));
}
// LOG.info(path.toString());
Vec3i pos = getRegionLoc(chunkPos);
int shortOffset = (offsetBytes + 1) * (pos.z + regionSize.z * (pos.y + regionSize.y * pos.x));
int fullOffset = (offsetBytes + 1) * (chunksPerRegion);
input.position(shortOffset);
int offset = 0;
for (int i = 0; i < offsetBytes; i++) {
offset *= 256;
offset += input.get();
}
int sectorLength = input.get();
input.position(fullOffset + sectorSize * offset);
// LOG.info("Read {} sectors", sectorLength);
byte tempData[] = new byte[sectorSize * sectorLength];
input.get(tempData);
DataInputStream trueInput = new DataInputStream(
new InflaterInputStream(new BufferedInputStream(new ByteArrayInputStream(tempData)))
);
DefaultChunkData chunk = ChunkIO.load(world, chunkPos, trueInput, IOContext.SAVE);
readGenerationHint(chunk, trueInput, server);
return chunk;
}
catch (EOFException e)
{
LOG.warn("Reached end of file");
e.printStackTrace();
}
return null;
}
private static void readGenerationHint(DefaultChunkData chunk, DataInputStream input, Server server) private static void readGenerationHint(DefaultChunkData chunk, DataInputStream input, Server server)
throws IOException, throws IOException,
DecodingException { DecodingException {

View File

@ -21,4 +21,13 @@ LayerTestGUI.PlacementModeHint = (Blocks %s Tiles: Ctrl + Mouse Wheel)
LayerTestGUI.IsFullscreen = Fullscreen: %5s (F11) LayerTestGUI.IsFullscreen = Fullscreen: %5s (F11)
LayerTestGUI.IsVSync = VSync: %5s (F12) LayerTestGUI.IsVSync = VSync: %5s (F12)
LayerButtonTest.Title = Button Test LayerButtonTest.Title = Button Test
LayerButtonTest.Return = Back To Menu
LayerTitle.Title = Progressia
LayerTitle.Play = Play World
LayerTitle.Options = Options
LayerTitle.Quit = Quit
LayerText.Load = Loading...
LayerText.Save = Saving...

View File

@ -21,4 +21,13 @@ LayerTestGUI.PlacementModeHint = (Блок %s плитки: Ctrl + прокру
LayerTestGUI.IsFullscreen = Полный экран: %5s (F11) LayerTestGUI.IsFullscreen = Полный экран: %5s (F11)
LayerTestGUI.IsVSync = Верт. синхр.: %5s (F12) LayerTestGUI.IsVSync = Верт. синхр.: %5s (F12)
LayerButtonTest.Title = Тест Кнопок LayerButtonTest.Title = Тест Кнопок
LayerButtonTest.Return = Back To Menu [[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[
LayerTitle.Title = Прогрессия
LayerTitle.Play = ???????
LayerTitle.Options = ????????
LayerTitle.Quit = ????????
LayerText.Load = Loading... (Change)
LayerText.Save = Saving...(Cahnsf)

View File

@ -26,6 +26,7 @@
<Logger name="Ticker Coordinator" level="DEBUG" /> <Logger name="Ticker Coordinator" level="DEBUG" />
<Logger name="Ticker 0" level="DEBUG" /> <Logger name="Ticker 0" level="DEBUG" />
--> -->
<!-- <Logger name="TestWorldDiskIO" level="DEBUG" /> -->
<Root level="info"> <Root level="info">
<AppenderRef ref="FileLog" /> <AppenderRef ref="FileLog" />