mirror of
https://github.com/Retera/WarsmashModEngine.git
synced 2022-07-31 17:38:59 +02:00
Snapshot after breaking scene, work on FDF, work on JASS
This commit is contained in:
parent
521aa51d95
commit
813e7c9d9b
10
build.gradle
10
build.gradle
@ -66,6 +66,7 @@ project(":core") {
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compile project(":fdfparser")
|
compile project(":fdfparser")
|
||||||
|
compile project(":jassparser")
|
||||||
compile "com.badlogicgames.gdx:gdx:$gdxVersion"
|
compile "com.badlogicgames.gdx:gdx:$gdxVersion"
|
||||||
compile "com.badlogicgames.gdx:gdx-box2d:$gdxVersion"
|
compile "com.badlogicgames.gdx:gdx-box2d:$gdxVersion"
|
||||||
compile "com.badlogicgames.gdx:gdx-freetype:$gdxVersion"
|
compile "com.badlogicgames.gdx:gdx-freetype:$gdxVersion"
|
||||||
@ -85,6 +86,15 @@ project(":fdfparser") {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
project(":jassparser") {
|
||||||
|
apply plugin: "antlr"
|
||||||
|
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
antlr "org.antlr:antlr4:$antlrVersion" // use antlr version 4
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
tasks.eclipse.doLast {
|
tasks.eclipse.doLast {
|
||||||
delete ".project"
|
delete ".project"
|
||||||
}
|
}
|
@ -7,6 +7,7 @@ import java.util.Arrays;
|
|||||||
|
|
||||||
import com.badlogic.gdx.ApplicationAdapter;
|
import com.badlogic.gdx.ApplicationAdapter;
|
||||||
import com.badlogic.gdx.Gdx;
|
import com.badlogic.gdx.Gdx;
|
||||||
|
import com.badlogic.gdx.audio.Music;
|
||||||
import com.badlogic.gdx.graphics.GL20;
|
import com.badlogic.gdx.graphics.GL20;
|
||||||
import com.badlogic.gdx.graphics.g2d.BitmapFont;
|
import com.badlogic.gdx.graphics.g2d.BitmapFont;
|
||||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
|
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
|
||||||
@ -18,6 +19,7 @@ import com.etheller.warsmash.datasources.DataSource;
|
|||||||
import com.etheller.warsmash.datasources.DataSourceDescriptor;
|
import com.etheller.warsmash.datasources.DataSourceDescriptor;
|
||||||
import com.etheller.warsmash.datasources.FolderDataSourceDescriptor;
|
import com.etheller.warsmash.datasources.FolderDataSourceDescriptor;
|
||||||
import com.etheller.warsmash.parsers.mdlx.Sequence;
|
import com.etheller.warsmash.parsers.mdlx.Sequence;
|
||||||
|
import com.etheller.warsmash.util.DataSourceFileHandle;
|
||||||
import com.etheller.warsmash.viewer5.Camera;
|
import com.etheller.warsmash.viewer5.Camera;
|
||||||
import com.etheller.warsmash.viewer5.CanvasProvider;
|
import com.etheller.warsmash.viewer5.CanvasProvider;
|
||||||
import com.etheller.warsmash.viewer5.ModelViewer;
|
import com.etheller.warsmash.viewer5.ModelViewer;
|
||||||
@ -72,7 +74,7 @@ public class WarsmashGdxGame extends ApplicationAdapter implements CanvasProvide
|
|||||||
this.cameraManager = new CameraManager();
|
this.cameraManager = new CameraManager();
|
||||||
this.cameraManager.setupCamera(scene);
|
this.cameraManager.setupCamera(scene);
|
||||||
|
|
||||||
this.mainModel = (MdxModel) this.viewer.load("Buildings\\Other\\TempArtB\\TempArtB.mdx",
|
this.mainModel = (MdxModel) this.viewer.load("UI\\Glues\\MainMenu\\MainMenu3d\\MainMenu3d.mdx",
|
||||||
// this.mainModel = (MdxModel) this.viewer.load("Abilities\\Spells\\Orc\\FeralSpirit\\feralspirittarget.mdx",
|
// this.mainModel = (MdxModel) this.viewer.load("Abilities\\Spells\\Orc\\FeralSpirit\\feralspirittarget.mdx",
|
||||||
new PathSolver() {
|
new PathSolver() {
|
||||||
@Override
|
@Override
|
||||||
@ -88,7 +90,7 @@ public class WarsmashGdxGame extends ApplicationAdapter implements CanvasProvide
|
|||||||
// System.out.println(Arrays.toString(evt.keyFrames));
|
// System.out.println(Arrays.toString(evt.keyFrames));
|
||||||
// System.out.println(evt.name);
|
// System.out.println(evt.name);
|
||||||
|
|
||||||
// this.modelCamera = this.mainModel.cameras.get(0);
|
this.modelCamera = this.mainModel.cameras.get(0);
|
||||||
|
|
||||||
this.mainInstance = (MdxComplexInstance) this.mainModel.addInstance(0);
|
this.mainInstance = (MdxComplexInstance) this.mainModel.addInstance(0);
|
||||||
|
|
||||||
@ -96,14 +98,21 @@ public class WarsmashGdxGame extends ApplicationAdapter implements CanvasProvide
|
|||||||
|
|
||||||
int animIndex = 0;
|
int animIndex = 0;
|
||||||
for (final Sequence s : this.mainModel.getSequences()) {
|
for (final Sequence s : this.mainModel.getSequences()) {
|
||||||
if (s.getName().toLowerCase().startsWith("walk")) {
|
if (s.getName().toLowerCase().startsWith("stand")) {
|
||||||
animIndex = this.mainModel.getSequences().indexOf(s);
|
animIndex = this.mainModel.getSequences().indexOf(s);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.mainInstance.setSequence(animIndex);
|
this.mainInstance.setSequence(animIndex);
|
||||||
|
|
||||||
this.mainInstance.setSequenceLoopMode(0);
|
this.mainInstance.setSequenceLoopMode(0);
|
||||||
|
|
||||||
|
final Music music = Gdx.audio
|
||||||
|
.newMusic(new DataSourceFileHandle(this.viewer.dataSource, "Sound\\Music\\mp3Music\\MainScreen.mp3"));
|
||||||
|
music.setVolume(0.2f);
|
||||||
|
music.setLooping(true);
|
||||||
|
music.play();
|
||||||
|
|
||||||
// acolytesHarvestingSceneJoke2(scene);
|
// acolytesHarvestingSceneJoke2(scene);
|
||||||
|
|
||||||
System.out.println("Loaded");
|
System.out.println("Loaded");
|
||||||
@ -489,7 +498,7 @@ public class WarsmashGdxGame extends ApplicationAdapter implements CanvasProvide
|
|||||||
WarsmashGdxGame.this.cameraPositionTemp[1], WarsmashGdxGame.this.cameraPositionTemp[2]);
|
WarsmashGdxGame.this.cameraPositionTemp[1], WarsmashGdxGame.this.cameraPositionTemp[2]);
|
||||||
this.target.add(WarsmashGdxGame.this.cameraTargetTemp[0], WarsmashGdxGame.this.cameraTargetTemp[1],
|
this.target.add(WarsmashGdxGame.this.cameraTargetTemp[0], WarsmashGdxGame.this.cameraTargetTemp[1],
|
||||||
WarsmashGdxGame.this.cameraTargetTemp[2]);
|
WarsmashGdxGame.this.cameraTargetTemp[2]);
|
||||||
this.camera.perspective(WarsmashGdxGame.this.modelCamera.fieldOfView,
|
this.camera.perspective(WarsmashGdxGame.this.modelCamera.fieldOfView * 0.75f,
|
||||||
Gdx.graphics.getWidth() / (float) Gdx.graphics.getHeight(),
|
Gdx.graphics.getWidth() / (float) Gdx.graphics.getHeight(),
|
||||||
WarsmashGdxGame.this.modelCamera.nearClippingPlane,
|
WarsmashGdxGame.this.modelCamera.nearClippingPlane,
|
||||||
WarsmashGdxGame.this.modelCamera.farClippingPlane);
|
WarsmashGdxGame.this.modelCamera.farClippingPlane);
|
||||||
|
@ -14,7 +14,6 @@ import com.badlogic.gdx.ApplicationAdapter;
|
|||||||
import com.badlogic.gdx.Gdx;
|
import com.badlogic.gdx.Gdx;
|
||||||
import com.badlogic.gdx.Input;
|
import com.badlogic.gdx.Input;
|
||||||
import com.badlogic.gdx.InputProcessor;
|
import com.badlogic.gdx.InputProcessor;
|
||||||
import com.badlogic.gdx.audio.Music;
|
|
||||||
import com.badlogic.gdx.graphics.Color;
|
import com.badlogic.gdx.graphics.Color;
|
||||||
import com.badlogic.gdx.graphics.GL20;
|
import com.badlogic.gdx.graphics.GL20;
|
||||||
import com.badlogic.gdx.graphics.GL30;
|
import com.badlogic.gdx.graphics.GL30;
|
||||||
@ -37,6 +36,11 @@ import com.etheller.warsmash.datasources.CompoundDataSourceDescriptor;
|
|||||||
import com.etheller.warsmash.datasources.DataSource;
|
import com.etheller.warsmash.datasources.DataSource;
|
||||||
import com.etheller.warsmash.datasources.DataSourceDescriptor;
|
import com.etheller.warsmash.datasources.DataSourceDescriptor;
|
||||||
import com.etheller.warsmash.datasources.FolderDataSourceDescriptor;
|
import com.etheller.warsmash.datasources.FolderDataSourceDescriptor;
|
||||||
|
import com.etheller.warsmash.parsers.fdf.GameUI;
|
||||||
|
import com.etheller.warsmash.parsers.fdf.datamodel.AnchorDefinition;
|
||||||
|
import com.etheller.warsmash.parsers.fdf.datamodel.FramePoint;
|
||||||
|
import com.etheller.warsmash.parsers.fdf.frames.UIFrame;
|
||||||
|
import com.etheller.warsmash.units.Element;
|
||||||
import com.etheller.warsmash.util.DataSourceFileHandle;
|
import com.etheller.warsmash.util.DataSourceFileHandle;
|
||||||
import com.etheller.warsmash.util.ImageUtils;
|
import com.etheller.warsmash.util.ImageUtils;
|
||||||
import com.etheller.warsmash.util.WarsmashConstants;
|
import com.etheller.warsmash.util.WarsmashConstants;
|
||||||
@ -93,7 +97,13 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
|
|||||||
private boolean showTalentTree;
|
private boolean showTalentTree;
|
||||||
|
|
||||||
private final List<Message> messages = new LinkedList<>();
|
private final List<Message> messages = new LinkedList<>();
|
||||||
|
private MdxModel timeIndicator;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
*
|
||||||
|
* @see com.badlogic.gdx.ApplicationAdapter#create()
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void create() {
|
public void create() {
|
||||||
|
|
||||||
@ -126,7 +136,7 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
|
|||||||
this.viewer.worldScene.enableAudio();
|
this.viewer.worldScene.enableAudio();
|
||||||
this.viewer.enableAudio();
|
this.viewer.enableAudio();
|
||||||
try {
|
try {
|
||||||
this.viewer.loadMap("ReforgedGeorgeVacation.w3x");
|
this.viewer.loadMap("PeasantTest.w3x");
|
||||||
}
|
}
|
||||||
catch (final IOException e) {
|
catch (final IOException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
@ -143,6 +153,9 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
|
|||||||
this.portraitCameraManager = new CameraManager();
|
this.portraitCameraManager = new CameraManager();
|
||||||
this.portraitCameraManager.setupCamera(this.portraitScene);
|
this.portraitCameraManager.setupCamera(this.portraitScene);
|
||||||
|
|
||||||
|
this.uiScene = this.viewer.addScene();
|
||||||
|
this.uiScene.alpha = true;
|
||||||
|
|
||||||
// this.mainModel = (MdxModel) this.viewer.load("UI\\Glues\\MainMenu\\MainMenu3D_exp\\MainMenu3D_exp.mdx",
|
// this.mainModel = (MdxModel) this.viewer.load("UI\\Glues\\MainMenu\\MainMenu3D_exp\\MainMenu3D_exp.mdx",
|
||||||
|
|
||||||
this.portraitScene.camera.viewport(new Rectangle(100, 0, 6400, 48));
|
this.portraitScene.camera.viewport(new Rectangle(100, 0, 6400, 48));
|
||||||
@ -151,6 +164,13 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
|
|||||||
final float w = Gdx.graphics.getWidth();
|
final float w = Gdx.graphics.getWidth();
|
||||||
final float h = Gdx.graphics.getHeight();
|
final float h = Gdx.graphics.getHeight();
|
||||||
|
|
||||||
|
this.tempRect.x = 0;
|
||||||
|
this.tempRect.y = 0;
|
||||||
|
this.tempRect.width = w;
|
||||||
|
this.tempRect.height = h;
|
||||||
|
this.uiScene.camera.viewport(this.tempRect);
|
||||||
|
this.uiScene.camera.ortho(0, 0.8f, 0, 0.6f, 0, 1);
|
||||||
|
|
||||||
final FreeTypeFontGenerator fontGenerator = new FreeTypeFontGenerator(
|
final FreeTypeFontGenerator fontGenerator = new FreeTypeFontGenerator(
|
||||||
new DataSourceFileHandle(this.viewer.dataSource, "fonts\\FRIZQT__.TTF"));
|
new DataSourceFileHandle(this.viewer.dataSource, "fonts\\FRIZQT__.TTF"));
|
||||||
final FreeTypeFontParameter fontParam = new FreeTypeFontParameter();
|
final FreeTypeFontParameter fontParam = new FreeTypeFontParameter();
|
||||||
@ -212,13 +232,13 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
|
|||||||
|
|
||||||
Gdx.input.setInputProcessor(this);
|
Gdx.input.setInputProcessor(this);
|
||||||
|
|
||||||
final Music music = Gdx.audio
|
// final Music music = Gdx.audio
|
||||||
.newMusic(new DataSourceFileHandle(this.viewer.dataSource, "Sound\\Music\\mp3Music\\DarkAgents.mp3"));
|
// .newMusic(new DataSourceFileHandle(this.viewer.dataSource, "Sound\\Music\\mp3Music\\DarkAgents.mp3"));
|
||||||
music.setVolume(0.2f);
|
// music.setVolume(0.2f);
|
||||||
music.setLooping(true);
|
// music.setLooping(true);
|
||||||
music.play();
|
// music.play();
|
||||||
|
|
||||||
this.minimap = new Rectangle(35, 7, 305, 272);
|
this.minimap = new Rectangle(18.75f, 13.75f, 278.75f, 276.25f);
|
||||||
final float worldWidth = (this.viewer.terrain.columns - 1);
|
final float worldWidth = (this.viewer.terrain.columns - 1);
|
||||||
final float worldHeight = this.viewer.terrain.rows - 1;
|
final float worldHeight = this.viewer.terrain.rows - 1;
|
||||||
final float worldSize = Math.max(worldWidth, worldHeight);
|
final float worldSize = Math.max(worldWidth, worldHeight);
|
||||||
@ -234,6 +254,33 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
|
|||||||
|
|
||||||
this.shapeRenderer = new ShapeRenderer();
|
this.shapeRenderer = new ShapeRenderer();
|
||||||
this.talentTreeWindow = new Rectangle(100, 300, 1400, 800);
|
this.talentTreeWindow = new Rectangle(100, 300, 1400, 800);
|
||||||
|
|
||||||
|
final Element skin = GameUI.loadSkin(this.viewer.dataSource, "Human");
|
||||||
|
this.gameUI = new GameUI(this.viewer.dataSource, skin, this.uiViewport);
|
||||||
|
String timeIndicatorPath = skin.getField("TimeOfDayIndicator");
|
||||||
|
if (!this.viewer.dataSource.has(timeIndicatorPath)) {
|
||||||
|
final int lastDotIndex = timeIndicatorPath.lastIndexOf('.');
|
||||||
|
if (lastDotIndex >= 0) {
|
||||||
|
timeIndicatorPath = timeIndicatorPath.substring(0, lastDotIndex);
|
||||||
|
}
|
||||||
|
timeIndicatorPath += ".mdx";
|
||||||
|
}
|
||||||
|
this.timeIndicator = (MdxModel) this.viewer.load(timeIndicatorPath, this.viewer.mapPathSolver,
|
||||||
|
this.viewer.solverParams);
|
||||||
|
final MdxComplexInstance timeIndicatorInstance = (MdxComplexInstance) this.timeIndicator.addInstance();
|
||||||
|
timeIndicatorInstance.setScene(this.uiScene);
|
||||||
|
timeIndicatorInstance.setSequence(0);
|
||||||
|
timeIndicatorInstance.setSequenceLoopMode(2);
|
||||||
|
try {
|
||||||
|
this.gameUI.loadTOCFile("UI\\FrameDef\\FrameDef.toc");
|
||||||
|
}
|
||||||
|
catch (final IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
this.gameUI.createSimpleFrame("ConsoleUI", this.gameUI, 0);
|
||||||
|
final UIFrame resourceBarFrame = this.gameUI.createSimpleFrame("ResourceBarFrame", this.gameUI, 0);
|
||||||
|
resourceBarFrame.addAnchor(new AnchorDefinition(FramePoint.TOPRIGHT, 0, 0));
|
||||||
|
this.gameUI.positionBounds(this.uiViewport);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -270,60 +317,35 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
|
|||||||
this.uiViewport.apply();
|
this.uiViewport.apply();
|
||||||
this.batch.setProjectionMatrix(this.uiCamera.combined);
|
this.batch.setProjectionMatrix(this.uiCamera.combined);
|
||||||
this.batch.begin();
|
this.batch.begin();
|
||||||
|
this.gameUI.render(this.batch);
|
||||||
this.font.setColor(Color.YELLOW);
|
this.font.setColor(Color.YELLOW);
|
||||||
final String fpsString = "FPS: " + Gdx.graphics.getFramesPerSecond();
|
final String fpsString = "FPS: " + Gdx.graphics.getFramesPerSecond();
|
||||||
this.glyphLayout.setText(this.font, fpsString);
|
this.glyphLayout.setText(this.font, fpsString);
|
||||||
this.font.draw(this.batch, fpsString, (this.uiViewport.getWorldWidth() - this.glyphLayout.width) / 2, 1100);
|
this.font.draw(this.batch, fpsString, (this.uiViewport.getWorldWidth() - this.glyphLayout.width) / 2, 1100);
|
||||||
|
|
||||||
// this.batch.draw(this.consoleUITexture, 0, 0, this.uiViewport.getWorldWidth(), 320);
|
this.batch.draw(this.minimapTexture, this.minimap.x, this.minimap.y, this.minimap.width, this.minimap.height);
|
||||||
this.batch.draw(this.minimapTexture, 35, 7, 305, 272);
|
|
||||||
|
|
||||||
if (this.selectedUnit != null) {
|
if (this.selectedUnit != null) {
|
||||||
this.font24.setColor(Color.WHITE);
|
|
||||||
final String name = this.viewer.simulation.getUnitData()
|
|
||||||
.getName(this.selectedUnit.getSimulationUnit().getTypeId());
|
|
||||||
this.glyphLayout.setText(this.font24, name);
|
|
||||||
this.font24.draw(this.batch, name, ((this.uiViewport.getWorldWidth() - this.glyphLayout.width) / 2) + 100,
|
|
||||||
200);
|
|
||||||
|
|
||||||
this.font20.setColor(Color.YELLOW);
|
|
||||||
this.font20.draw(this.batch, "Attack:", 600, 120);
|
|
||||||
this.font20.draw(this.batch, "Defense:", 600, 98);
|
|
||||||
this.font20.draw(this.batch, "Speed:", 600, 76);
|
|
||||||
this.font20.setColor(Color.WHITE);
|
|
||||||
int messageIndex = 0;
|
int messageIndex = 0;
|
||||||
for (final Message message : this.messages) {
|
for (final Message message : this.messages) {
|
||||||
this.font20.draw(this.batch, message.text, 100, 400 + (25 * (messageIndex++)));
|
this.font20.draw(this.batch, message.text, 100, 400 + (25 * (messageIndex++)));
|
||||||
}
|
}
|
||||||
this.font20.setColor(Color.WHITE);
|
this.font20.setColor(Color.WHITE);
|
||||||
final int dmgMin = this.viewer.simulation.getUnitData()
|
|
||||||
.getA1MinDamage(this.selectedUnit.getSimulationUnit().getTypeId());
|
|
||||||
final int dmgMax = this.viewer.simulation.getUnitData()
|
|
||||||
.getA1MaxDamage(this.selectedUnit.getSimulationUnit().getTypeId());
|
|
||||||
final int def = this.viewer.simulation.getUnitData()
|
|
||||||
.getDefense(this.selectedUnit.getSimulationUnit().getTypeId());
|
|
||||||
this.font20.draw(this.batch, Integer.toString(dmgMin) + " - " + Integer.toString(dmgMax), 700, 120);
|
|
||||||
this.font20.draw(this.batch, Integer.toString(def), 700, 98);
|
|
||||||
this.font20.draw(this.batch, Integer.toString(this.selectedUnit.getSimulationUnit().getSpeed()), 700, 76);
|
|
||||||
|
|
||||||
final COrder currentOrder = this.selectedUnit.getSimulationUnit().getCurrentOrder();
|
final COrder currentOrder = this.selectedUnit.getSimulationUnit().getCurrentOrder();
|
||||||
for (final CommandCardIcon commandCardIcon : this.selectedUnit.getCommandCardIcons()) {
|
for (final CommandCardIcon commandCardIcon : this.selectedUnit.getCommandCardIcons()) {
|
||||||
this.batch.draw(commandCardIcon.getTexture(), 1225 + (70 * commandCardIcon.getX()),
|
this.batch.draw(commandCardIcon.getTexture(), 1235 + (86.8f * commandCardIcon.getX()),
|
||||||
160 - (70 * commandCardIcon.getY()), 64, 64);
|
190 - (88 * commandCardIcon.getY()), 78f, 78f);
|
||||||
if (((currentOrder != null) && (currentOrder.getOrderId() == commandCardIcon.getOrderId()))
|
if (((currentOrder != null) && (currentOrder.getOrderId() == commandCardIcon.getOrderId()))
|
||||||
|| ((currentOrder == null) && (commandCardIcon.getOrderId() == CAbilityStop.ORDER_ID))) {
|
|| ((currentOrder == null) && (commandCardIcon.getOrderId() == CAbilityStop.ORDER_ID))) {
|
||||||
final int blendDstFunc = this.batch.getBlendDstFunc();
|
final int blendDstFunc = this.batch.getBlendDstFunc();
|
||||||
final int blendSrcFunc = this.batch.getBlendSrcFunc();
|
final int blendSrcFunc = this.batch.getBlendSrcFunc();
|
||||||
this.batch.setBlendFunction(GL20.GL_SRC_ALPHA, GL20.GL_ONE);
|
this.batch.setBlendFunction(GL20.GL_SRC_ALPHA, GL20.GL_ONE);
|
||||||
this.batch.draw(this.activeButtonTexture, 1225 + (70 * commandCardIcon.getX()),
|
this.batch.draw(this.activeButtonTexture, 1235 + (86.8f * commandCardIcon.getX()),
|
||||||
160 - (70 * commandCardIcon.getY()), 64, 64);
|
190 - (88 * commandCardIcon.getY()), 78f, 78f);
|
||||||
this.batch.setBlendFunction(blendSrcFunc, blendDstFunc);
|
this.batch.setBlendFunction(blendSrcFunc, blendDstFunc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.batch.draw(this.solidGreenTexture, 413, 34, 122 * (this.selectedUnit.getSimulationUnit().getLife()
|
|
||||||
/ this.selectedUnit.getSimulationUnit().getMaximumLife()), 7);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
for (final RenderUnit unit : this.viewer.units) {
|
for (final RenderUnit unit : this.viewer.units) {
|
||||||
if (unit.playerIndex >= WarsmashConstants.MAX_PLAYERS) {
|
if (unit.playerIndex >= WarsmashConstants.MAX_PLAYERS) {
|
||||||
@ -387,9 +409,11 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
|
|||||||
public void resize(final int width, final int height) {
|
public void resize(final int width, final int height) {
|
||||||
super.resize(width, height);
|
super.resize(width, height);
|
||||||
this.tempRect.x = 0;
|
this.tempRect.x = 0;
|
||||||
this.tempRect.y = 0;
|
|
||||||
this.tempRect.width = width;
|
this.tempRect.width = width;
|
||||||
this.tempRect.height = height;
|
final float topHeight = 0.02666f * height;
|
||||||
|
final float bottomHeight = 0.21333f * height;
|
||||||
|
this.tempRect.y = (int) bottomHeight;
|
||||||
|
this.tempRect.height = height - (int) (topHeight + bottomHeight);
|
||||||
this.cameraManager.camera.viewport(this.tempRect);
|
this.cameraManager.camera.viewport(this.tempRect);
|
||||||
final float portraitTestWidth = (100 / 640f) * width;
|
final float portraitTestWidth = (100 / 640f) * width;
|
||||||
final float portraitTestHeight = (100 / 480f) * height;
|
final float portraitTestHeight = (100 / 480f) * height;
|
||||||
@ -397,15 +421,21 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
|
|||||||
this.uiViewport.update(width, height);
|
this.uiViewport.update(width, height);
|
||||||
this.uiCamera.position.set(this.uiCamera.viewportWidth / 2, this.uiCamera.viewportHeight / 2, 0);
|
this.uiCamera.position.set(this.uiCamera.viewportWidth / 2, this.uiCamera.viewportHeight / 2, 0);
|
||||||
|
|
||||||
positionPortrait();
|
this.tempRect.x = this.uiViewport.getScreenX();
|
||||||
|
this.tempRect.y = this.uiViewport.getScreenY();
|
||||||
|
this.tempRect.width = this.uiViewport.getScreenWidth();
|
||||||
|
this.tempRect.height = this.uiViewport.getScreenHeight();
|
||||||
|
this.uiScene.camera.viewport(this.tempRect);
|
||||||
|
this.uiScene.camera.ortho(0f, 0.8f, 0f, 0.6f, -1f, 1);
|
||||||
|
|
||||||
|
positionPortrait();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void positionPortrait() {
|
private void positionPortrait() {
|
||||||
this.projectionTemp1.x = 385;
|
this.projectionTemp1.x = 422;
|
||||||
this.projectionTemp1.y = 0;
|
this.projectionTemp1.y = 57;
|
||||||
this.projectionTemp2.x = 385 + 180;
|
this.projectionTemp2.x = 422 + 167;
|
||||||
this.projectionTemp2.y = 177;
|
this.projectionTemp2.y = 57 + 170;
|
||||||
this.uiViewport.project(this.projectionTemp1);
|
this.uiViewport.project(this.projectionTemp1);
|
||||||
this.uiViewport.project(this.projectionTemp2);
|
this.uiViewport.project(this.projectionTemp2);
|
||||||
|
|
||||||
@ -492,7 +522,7 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
|
|||||||
WarsmashGdxMapGame.this.cameraPositionTemp[1], WarsmashGdxMapGame.this.cameraPositionTemp[2]);
|
WarsmashGdxMapGame.this.cameraPositionTemp[1], WarsmashGdxMapGame.this.cameraPositionTemp[2]);
|
||||||
this.target.add(WarsmashGdxMapGame.this.cameraTargetTemp[0],
|
this.target.add(WarsmashGdxMapGame.this.cameraTargetTemp[0],
|
||||||
WarsmashGdxMapGame.this.cameraTargetTemp[1], WarsmashGdxMapGame.this.cameraTargetTemp[2]);
|
WarsmashGdxMapGame.this.cameraTargetTemp[1], WarsmashGdxMapGame.this.cameraTargetTemp[2]);
|
||||||
this.camera.perspective(this.modelCamera.fieldOfView, this.camera.getAspect(),
|
this.camera.perspective(this.modelCamera.fieldOfView * 0.75f, this.camera.getAspect(),
|
||||||
this.modelCamera.nearClippingPlane, this.modelCamera.farClippingPlane);
|
this.modelCamera.nearClippingPlane, this.modelCamera.farClippingPlane);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -509,6 +539,8 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
|
|||||||
private Scene portraitScene;
|
private Scene portraitScene;
|
||||||
private Texture minimapTexture;
|
private Texture minimapTexture;
|
||||||
private Rectangle talentTreeWindow;
|
private Rectangle talentTreeWindow;
|
||||||
|
private GameUI gameUI;
|
||||||
|
private Scene uiScene;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean keyDown(final int keycode) {
|
public boolean keyDown(final int keycode) {
|
||||||
@ -551,6 +583,7 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean touchDown(final int screenX, final int screenY, final int pointer, final int button) {
|
public boolean touchDown(final int screenX, final int screenY, final int pointer, final int button) {
|
||||||
|
final float worldScreenY = getHeight() - screenY;
|
||||||
System.out.println(screenX + "," + screenY);
|
System.out.println(screenX + "," + screenY);
|
||||||
|
|
||||||
clickLocationTemp2.x = screenX;
|
clickLocationTemp2.x = screenX;
|
||||||
@ -559,8 +592,8 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
|
|||||||
|
|
||||||
if (this.selectedUnit != null) {
|
if (this.selectedUnit != null) {
|
||||||
for (final CommandCardIcon commandCardIcon : this.selectedUnit.getCommandCardIcons()) {
|
for (final CommandCardIcon commandCardIcon : this.selectedUnit.getCommandCardIcons()) {
|
||||||
if (new Rectangle(1225 + (70 * commandCardIcon.getX()), 160 - (70 * commandCardIcon.getY()), 64, 64)
|
if (new Rectangle(1235 + (86.8f * commandCardIcon.getX()), 190 - (88 * commandCardIcon.getY()), 78f,
|
||||||
.contains(clickLocationTemp2)) {
|
78f).contains(clickLocationTemp2)) {
|
||||||
if (button == Input.Buttons.RIGHT) {
|
if (button == Input.Buttons.RIGHT) {
|
||||||
this.messages.add(new Message(Gdx.input.getCurrentEventTime(), "Right mouse click"));
|
this.messages.add(new Message(Gdx.input.getCurrentEventTime(), "Right mouse click"));
|
||||||
}
|
}
|
||||||
@ -581,14 +614,14 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (button == Input.Buttons.RIGHT) {
|
if (button == Input.Buttons.RIGHT) {
|
||||||
final RenderUnit rayPickUnit = this.viewer.rayPickUnit(screenX, screenY);
|
final RenderUnit rayPickUnit = this.viewer.rayPickUnit(screenX, worldScreenY);
|
||||||
if ((rayPickUnit != null) && (rayPickUnit.playerIndex != this.selectedUnit.playerIndex)) {
|
if ((rayPickUnit != null) && (rayPickUnit.playerIndex != this.selectedUnit.playerIndex)) {
|
||||||
if (this.viewer.orderSmart(rayPickUnit)) {
|
if (this.viewer.orderSmart(rayPickUnit)) {
|
||||||
StandSequence.randomPortraitTalkSequence(this.portraitInstance);
|
StandSequence.randomPortraitTalkSequence(this.portraitInstance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this.viewer.getClickLocation(clickLocationTemp, screenX, screenY);
|
this.viewer.getClickLocation(clickLocationTemp, screenX, (int) worldScreenY);
|
||||||
System.out.println(clickLocationTemp);
|
System.out.println(clickLocationTemp);
|
||||||
this.viewer.showConfirmation(clickLocationTemp, 0, 1, 0);
|
this.viewer.showConfirmation(clickLocationTemp, 0, 1, 0);
|
||||||
final int x = (int) ((clickLocationTemp.x - this.viewer.terrain.centerOffset[0]) / 128);
|
final int x = (int) ((clickLocationTemp.x - this.viewer.terrain.centerOffset[0]) / 128);
|
||||||
@ -601,7 +634,7 @@ public class WarsmashGdxMapGame extends ApplicationAdapter implements CanvasProv
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
final List<RenderUnit> selectedUnits = this.viewer.selectUnit(screenX, screenY, false);
|
final List<RenderUnit> selectedUnits = this.viewer.selectUnit(screenX, worldScreenY, false);
|
||||||
if (!selectedUnits.isEmpty()) {
|
if (!selectedUnits.isEmpty()) {
|
||||||
final RenderUnit unit = selectedUnits.get(0);
|
final RenderUnit unit = selectedUnits.get(0);
|
||||||
this.selectedUnit = unit;
|
this.selectedUnit = unit;
|
||||||
|
11
core/src/com/etheller/warsmash/gameui/FDFGameUI.java
Normal file
11
core/src/com/etheller/warsmash/gameui/FDFGameUI.java
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
package com.etheller.warsmash.gameui;
|
||||||
|
|
||||||
|
import com.etheller.warsmash.parsers.fdf.datamodel.FrameTemplateEnvironment;
|
||||||
|
|
||||||
|
public class FDFGameUI {
|
||||||
|
private final FrameTemplateEnvironment frameTemplateEnvironment;
|
||||||
|
|
||||||
|
public FDFGameUI(final FrameTemplateEnvironment frameTemplateEnvironment) {
|
||||||
|
this.frameTemplateEnvironment = frameTemplateEnvironment;
|
||||||
|
}
|
||||||
|
}
|
200
core/src/com/etheller/warsmash/parsers/fdf/GameUI.java
Normal file
200
core/src/com/etheller/warsmash/parsers/fdf/GameUI.java
Normal file
@ -0,0 +1,200 @@
|
|||||||
|
package com.etheller.warsmash.parsers.fdf;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import com.badlogic.gdx.graphics.Texture;
|
||||||
|
import com.badlogic.gdx.graphics.g2d.TextureRegion;
|
||||||
|
import com.badlogic.gdx.utils.viewport.Viewport;
|
||||||
|
import com.etheller.warsmash.datasources.DataSource;
|
||||||
|
import com.etheller.warsmash.fdfparser.FDFParser;
|
||||||
|
import com.etheller.warsmash.fdfparser.FrameDefinitionVisitor;
|
||||||
|
import com.etheller.warsmash.parsers.fdf.datamodel.AnchorDefinition;
|
||||||
|
import com.etheller.warsmash.parsers.fdf.datamodel.FrameClass;
|
||||||
|
import com.etheller.warsmash.parsers.fdf.datamodel.FrameDefinition;
|
||||||
|
import com.etheller.warsmash.parsers.fdf.datamodel.FrameTemplateEnvironment;
|
||||||
|
import com.etheller.warsmash.parsers.fdf.datamodel.Vector4Definition;
|
||||||
|
import com.etheller.warsmash.parsers.fdf.frames.AbstractUIFrame;
|
||||||
|
import com.etheller.warsmash.parsers.fdf.frames.SimpleFrame;
|
||||||
|
import com.etheller.warsmash.parsers.fdf.frames.TextureFrame;
|
||||||
|
import com.etheller.warsmash.parsers.fdf.frames.UIFrame;
|
||||||
|
import com.etheller.warsmash.units.DataTable;
|
||||||
|
import com.etheller.warsmash.units.Element;
|
||||||
|
import com.etheller.warsmash.util.ImageUtils;
|
||||||
|
import com.etheller.warsmash.util.StringBundle;
|
||||||
|
|
||||||
|
public final class GameUI extends AbstractUIFrame implements UIFrame {
|
||||||
|
|
||||||
|
private final DataSource dataSource;
|
||||||
|
private final Element skin;
|
||||||
|
private final Viewport viewport;
|
||||||
|
private final FrameTemplateEnvironment templates;
|
||||||
|
private final Map<String, Texture> pathToTexture = new HashMap<>();
|
||||||
|
private final boolean autoPosition = false;
|
||||||
|
|
||||||
|
public GameUI(final DataSource dataSource, final Element skin, final Viewport viewport) {
|
||||||
|
super("GameUI", null);
|
||||||
|
this.dataSource = dataSource;
|
||||||
|
this.skin = skin;
|
||||||
|
this.viewport = viewport;
|
||||||
|
this.renderBounds.set(0, 0, viewport.getWorldWidth(), viewport.getWorldHeight());
|
||||||
|
this.templates = new FrameTemplateEnvironment();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Element loadSkin(final DataSource dataSource, final String skin) {
|
||||||
|
final DataTable skinsTable = new DataTable(StringBundle.EMPTY);
|
||||||
|
try (InputStream stream = dataSource.getResourceAsStream("UI\\war3skins.txt")) {
|
||||||
|
skinsTable.readTXT(stream, true);
|
||||||
|
}
|
||||||
|
catch (final IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
// final Element main = skinsTable.get("Main");
|
||||||
|
// final String skinsField = main.getField("Skins");
|
||||||
|
// final String[] skins = skinsField.split(",");
|
||||||
|
final Element defaultSkin = skinsTable.get("Default");
|
||||||
|
final Element userSkin = skinsTable.get(skin);
|
||||||
|
for (final String key : defaultSkin.keySet()) {
|
||||||
|
if (!userSkin.hasField(key)) {
|
||||||
|
userSkin.setField(key, defaultSkin.getField(key));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return userSkin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void loadTOCFile(final String tocFilePath) throws IOException {
|
||||||
|
final DataSourceFDFParserBuilder dataSourceFDFParserBuilder = new DataSourceFDFParserBuilder(this.dataSource);
|
||||||
|
final FrameDefinitionVisitor fdfVisitor = new FrameDefinitionVisitor(this.templates,
|
||||||
|
dataSourceFDFParserBuilder);
|
||||||
|
try (BufferedReader reader = new BufferedReader(
|
||||||
|
new InputStreamReader(this.dataSource.getResourceAsStream(tocFilePath)))) {
|
||||||
|
String line;
|
||||||
|
int tocLines = 0;
|
||||||
|
while ((line = reader.readLine()) != null) {
|
||||||
|
final FDFParser firstFileParser = dataSourceFDFParserBuilder.build(line);
|
||||||
|
fdfVisitor.visit(firstFileParser.program());
|
||||||
|
tocLines++;
|
||||||
|
}
|
||||||
|
System.out.println("TOC file loaded " + tocLines + " lines");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public UIFrame createFrame(final String name, final UIFrame owner, final int priority, final int createContext) {
|
||||||
|
throw new UnsupportedOperationException("Not yet implemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
public UIFrame createSimpleFrame(final String name, final UIFrame owner, final int createContext) {
|
||||||
|
final FrameDefinition frameDefinition = this.templates.getFrame(name);
|
||||||
|
if (frameDefinition.getFrameClass() == FrameClass.Frame) {
|
||||||
|
if ("SIMPLEFRAME".equals(frameDefinition.getFrameType())) {
|
||||||
|
final UIFrame inflated = inflate(frameDefinition, owner, null);
|
||||||
|
if (this.autoPosition) {
|
||||||
|
inflated.positionBounds(this.viewport);
|
||||||
|
}
|
||||||
|
add(inflated);
|
||||||
|
return inflated;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UIFrame inflate(final FrameDefinition frameDefinition, final UIFrame parent,
|
||||||
|
final FrameDefinition parentDefinitionIfAvailable) {
|
||||||
|
UIFrame inflatedFrame = null;
|
||||||
|
switch (frameDefinition.getFrameClass()) {
|
||||||
|
case Frame:
|
||||||
|
if ("SIMPLEFRAME".equals(frameDefinition.getFrameType())) {
|
||||||
|
final SimpleFrame simpleFrame = new SimpleFrame(frameDefinition.getName(), parent);
|
||||||
|
for (final FrameDefinition childDefinition : frameDefinition.getInnerFrames()) {
|
||||||
|
simpleFrame.add(inflate(childDefinition, simpleFrame, frameDefinition));
|
||||||
|
}
|
||||||
|
inflatedFrame = simpleFrame;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Layer:
|
||||||
|
// NOT HANDLED YET
|
||||||
|
break;
|
||||||
|
case String:
|
||||||
|
break;
|
||||||
|
case Texture:
|
||||||
|
String file = frameDefinition.getString("File");
|
||||||
|
if (frameDefinition.has("DecorateFileNames") || ((parentDefinitionIfAvailable != null)
|
||||||
|
&& parentDefinitionIfAvailable.has("DecorateFileNames"))) {
|
||||||
|
if (this.skin.hasField(file)) {
|
||||||
|
file = this.skin.getField(file);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new IllegalStateException("Decorated file name lookup not available: " + file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
final Texture texture = loadTexture(file);
|
||||||
|
final Vector4Definition texCoord = frameDefinition.getVector4("TexCoord");
|
||||||
|
final TextureRegion texRegion;
|
||||||
|
if (texCoord != null) {
|
||||||
|
texRegion = new TextureRegion(texture, texCoord.getX(), texCoord.getZ(), texCoord.getY(),
|
||||||
|
texCoord.getW());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
texRegion = new TextureRegion(texture);
|
||||||
|
}
|
||||||
|
final TextureFrame textureFrame = new TextureFrame(frameDefinition.getName(), parent, texRegion);
|
||||||
|
inflatedFrame = textureFrame;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (inflatedFrame != null) {
|
||||||
|
final Float width = frameDefinition.getFloat("Width");
|
||||||
|
if (width != null) {
|
||||||
|
inflatedFrame.setWidth(convertX(this.viewport, width));
|
||||||
|
}
|
||||||
|
final Float height = frameDefinition.getFloat("Height");
|
||||||
|
if (height != null) {
|
||||||
|
inflatedFrame.setHeight(convertY(this.viewport, height));
|
||||||
|
}
|
||||||
|
for (final AnchorDefinition anchor : frameDefinition.getAnchors()) {
|
||||||
|
inflatedFrame.addAnchor(new AnchorDefinition(anchor.getMyPoint(),
|
||||||
|
convertX(this.viewport, anchor.getX()), convertY(this.viewport, anchor.getY())));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// TODO in production throw some kind of exception here
|
||||||
|
}
|
||||||
|
return inflatedFrame;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UIFrame createFrameByType(final String typeName, final String name, final UIFrame owner,
|
||||||
|
final String inherits, final int createContext) {
|
||||||
|
throw new UnsupportedOperationException("Not yet implemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float convertX(final Viewport viewport, final float fdfX) {
|
||||||
|
return (fdfX / 0.8f) * viewport.getWorldWidth();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static float convertY(final Viewport viewport, final float fdfY) {
|
||||||
|
return (fdfY / 0.6f) * viewport.getWorldHeight();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Texture loadTexture(String path) {
|
||||||
|
if (!path.contains(".")) {
|
||||||
|
path = path + ".blp";
|
||||||
|
}
|
||||||
|
Texture texture = this.pathToTexture.get(path);
|
||||||
|
if (texture == null) {
|
||||||
|
texture = ImageUtils.getBLPTexture(this.dataSource, path);
|
||||||
|
this.pathToTexture.put(path, texture);
|
||||||
|
}
|
||||||
|
return texture;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void positionBounds(final Viewport viewport) {
|
||||||
|
innerPositionBounds(viewport);
|
||||||
|
}
|
||||||
|
}
|
37
core/src/com/etheller/warsmash/parsers/fdf/ModelExport.java
Normal file
37
core/src/com/etheller/warsmash/parsers/fdf/ModelExport.java
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
package com.etheller.warsmash.parsers.fdf;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import com.etheller.warsmash.datasources.CompoundDataSourceDescriptor;
|
||||||
|
import com.etheller.warsmash.datasources.DataSource;
|
||||||
|
import com.etheller.warsmash.datasources.DataSourceDescriptor;
|
||||||
|
import com.etheller.warsmash.datasources.FolderDataSourceDescriptor;
|
||||||
|
import com.etheller.warsmash.parsers.mdlx.MdlxModel;
|
||||||
|
|
||||||
|
public class ModelExport {
|
||||||
|
|
||||||
|
public static void main(final String[] args) {
|
||||||
|
|
||||||
|
final FolderDataSourceDescriptor war3mpq = new FolderDataSourceDescriptor("E:\\Backups\\Warcraft\\Data\\127");
|
||||||
|
final FolderDataSourceDescriptor testingFolder = new FolderDataSourceDescriptor("E:\\Backups\\Warsmash\\Data");
|
||||||
|
final FolderDataSourceDescriptor currentFolder = new FolderDataSourceDescriptor(".");
|
||||||
|
final DataSource dataSource = new CompoundDataSourceDescriptor(
|
||||||
|
Arrays.<DataSourceDescriptor>asList(war3mpq, testingFolder, currentFolder)).createDataSource();
|
||||||
|
|
||||||
|
try (InputStream modelStream = dataSource
|
||||||
|
.getResourceAsStream("UI\\Glues\\MainMenu\\MainMenu3D\\MainMenu3D.mdx")) {
|
||||||
|
final MdlxModel model = new MdlxModel(modelStream);
|
||||||
|
try (FileOutputStream fos = new FileOutputStream(new File("C:\\Temp\\MainMenu3D.mdl"))) {
|
||||||
|
model.saveMdl(fos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (final IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,291 @@
|
|||||||
|
package com.etheller.warsmash.parsers.fdf.frames;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.badlogic.gdx.math.Rectangle;
|
||||||
|
import com.badlogic.gdx.utils.viewport.Viewport;
|
||||||
|
import com.etheller.warsmash.parsers.fdf.datamodel.AnchorDefinition;
|
||||||
|
import com.etheller.warsmash.parsers.fdf.datamodel.FramePoint;
|
||||||
|
|
||||||
|
public abstract class AbstractRenderableFrame implements UIFrame {
|
||||||
|
protected String name;
|
||||||
|
protected UIFrame parent;
|
||||||
|
protected boolean visible;
|
||||||
|
protected int level;
|
||||||
|
protected final Rectangle renderBounds = new Rectangle(0, 0, 0, 0); // in libgdx rendering space
|
||||||
|
protected List<AnchorDefinition> anchors = new ArrayList<>();
|
||||||
|
|
||||||
|
public AbstractRenderableFrame(final String name, final UIFrame parent) {
|
||||||
|
this.name = name;
|
||||||
|
this.parent = parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setWidth(final float width) {
|
||||||
|
this.renderBounds.width = width;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHeight(final float height) {
|
||||||
|
this.renderBounds.height = height;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasLeftAnchor() {
|
||||||
|
for (final AnchorDefinition anchor : this.anchors) {
|
||||||
|
switch (anchor.getMyPoint()) {
|
||||||
|
case CENTER:
|
||||||
|
case BOTTOM:
|
||||||
|
case TOP:
|
||||||
|
case BOTTOMRIGHT:
|
||||||
|
case RIGHT:
|
||||||
|
case TOPRIGHT:
|
||||||
|
break;
|
||||||
|
case BOTTOMLEFT:
|
||||||
|
case LEFT:
|
||||||
|
case TOPLEFT:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasRightAnchor() {
|
||||||
|
for (final AnchorDefinition anchor : this.anchors) {
|
||||||
|
switch (anchor.getMyPoint()) {
|
||||||
|
case CENTER:
|
||||||
|
case BOTTOM:
|
||||||
|
case TOP:
|
||||||
|
case BOTTOMLEFT:
|
||||||
|
case LEFT:
|
||||||
|
case TOPLEFT:
|
||||||
|
break;
|
||||||
|
case BOTTOMRIGHT:
|
||||||
|
case RIGHT:
|
||||||
|
case TOPRIGHT:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasTopAnchor() {
|
||||||
|
for (final AnchorDefinition anchor : this.anchors) {
|
||||||
|
switch (anchor.getMyPoint()) {
|
||||||
|
case CENTER:
|
||||||
|
case BOTTOM:
|
||||||
|
case BOTTOMLEFT:
|
||||||
|
case LEFT:
|
||||||
|
case BOTTOMRIGHT:
|
||||||
|
case RIGHT:
|
||||||
|
break;
|
||||||
|
case TOP:
|
||||||
|
case TOPLEFT:
|
||||||
|
case TOPRIGHT:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasBottomAnchor() {
|
||||||
|
for (final AnchorDefinition anchor : this.anchors) {
|
||||||
|
switch (anchor.getMyPoint()) {
|
||||||
|
case CENTER:
|
||||||
|
case LEFT:
|
||||||
|
case RIGHT:
|
||||||
|
case TOP:
|
||||||
|
case TOPLEFT:
|
||||||
|
case TOPRIGHT:
|
||||||
|
break;
|
||||||
|
case BOTTOM:
|
||||||
|
case BOTTOMLEFT:
|
||||||
|
case BOTTOMRIGHT:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float getFramePointX(final FramePoint framePoint) {
|
||||||
|
switch (framePoint) {
|
||||||
|
case CENTER:
|
||||||
|
case BOTTOM:
|
||||||
|
case TOP:
|
||||||
|
return this.renderBounds.x + (this.renderBounds.width / 2);
|
||||||
|
case BOTTOMLEFT:
|
||||||
|
case LEFT:
|
||||||
|
case TOPLEFT:
|
||||||
|
return this.renderBounds.x;
|
||||||
|
case BOTTOMRIGHT:
|
||||||
|
case RIGHT:
|
||||||
|
case TOPRIGHT:
|
||||||
|
return this.renderBounds.x + this.renderBounds.width;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFramePointX(final FramePoint framePoint, final float x) {
|
||||||
|
if (this.renderBounds.width == 0) {
|
||||||
|
this.renderBounds.x = x;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
switch (framePoint) {
|
||||||
|
case CENTER:
|
||||||
|
case BOTTOM:
|
||||||
|
case TOP:
|
||||||
|
this.renderBounds.x = x - (this.renderBounds.width / 2);
|
||||||
|
return;
|
||||||
|
case BOTTOMLEFT:
|
||||||
|
case LEFT:
|
||||||
|
case TOPLEFT:
|
||||||
|
if (hasRightAnchor()) {
|
||||||
|
final float oldRightX = this.renderBounds.x + this.renderBounds.width;
|
||||||
|
this.renderBounds.x = x;
|
||||||
|
this.renderBounds.width = oldRightX - x;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// no right anchor, keep width
|
||||||
|
this.renderBounds.x = x;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
case BOTTOMRIGHT:
|
||||||
|
case RIGHT:
|
||||||
|
case TOPRIGHT:
|
||||||
|
if (hasLeftAnchor()) {
|
||||||
|
this.renderBounds.width = x - this.renderBounds.x;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.renderBounds.x = x - this.renderBounds.width;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float getFramePointY(final FramePoint framePoint) {
|
||||||
|
switch (framePoint) {
|
||||||
|
case LEFT:
|
||||||
|
case CENTER:
|
||||||
|
case RIGHT:
|
||||||
|
return this.renderBounds.y + (this.renderBounds.height / 2);
|
||||||
|
case BOTTOMLEFT:
|
||||||
|
case BOTTOM:
|
||||||
|
case BOTTOMRIGHT:
|
||||||
|
return this.renderBounds.y;
|
||||||
|
case TOPLEFT:
|
||||||
|
case TOP:
|
||||||
|
case TOPRIGHT:
|
||||||
|
return this.renderBounds.y + this.renderBounds.height;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFramePointY(final FramePoint framePoint, final float y) {
|
||||||
|
if (this.renderBounds.height == 0) {
|
||||||
|
this.renderBounds.y = y;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
switch (framePoint) {
|
||||||
|
case LEFT:
|
||||||
|
case CENTER:
|
||||||
|
case RIGHT:
|
||||||
|
this.renderBounds.y = y - (this.renderBounds.height / 2);
|
||||||
|
return;
|
||||||
|
case TOPLEFT:
|
||||||
|
case TOP:
|
||||||
|
case TOPRIGHT:
|
||||||
|
if (hasBottomAnchor()) {
|
||||||
|
this.renderBounds.height = y - this.renderBounds.y;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.renderBounds.y = y - this.renderBounds.height;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
case BOTTOMLEFT:
|
||||||
|
case BOTTOM:
|
||||||
|
case BOTTOMRIGHT:
|
||||||
|
if (hasTopAnchor()) {
|
||||||
|
final float oldBottomY = this.renderBounds.y + this.renderBounds.height;
|
||||||
|
this.renderBounds.y = y;
|
||||||
|
this.renderBounds.height = oldBottomY - y;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.renderBounds.y = y;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addAnchor(final AnchorDefinition anchorDefinition) {
|
||||||
|
this.anchors.add(anchorDefinition);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void positionBounds(final Viewport viewport) {
|
||||||
|
if (this.parent == null) {
|
||||||
|
// TODO this is a bit of a hack, remove later
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ("ResourceBarFrame".equals(this.name)) {
|
||||||
|
System.out.println("doing resource bar");
|
||||||
|
}
|
||||||
|
if (this.anchors.isEmpty()) {
|
||||||
|
this.renderBounds.x = this.parent.getFramePointX(FramePoint.LEFT);
|
||||||
|
this.renderBounds.y = this.parent.getFramePointY(FramePoint.BOTTOM);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for (final AnchorDefinition anchor : this.anchors) {
|
||||||
|
final float parentPointX = this.parent.getFramePointX(anchor.getMyPoint());
|
||||||
|
final float parentPointY = this.parent.getFramePointY(anchor.getMyPoint());
|
||||||
|
setFramePointX(anchor.getMyPoint(), parentPointX + anchor.getX());
|
||||||
|
setFramePointY(anchor.getMyPoint(), parentPointY + anchor.getY());
|
||||||
|
System.out.println(getClass().getSimpleName() + ":" + this.name + " anchoring to: " + anchor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this.renderBounds.width == 0) {
|
||||||
|
this.renderBounds.width = this.parent.getFramePointX(FramePoint.RIGHT)
|
||||||
|
- this.parent.getFramePointX(FramePoint.LEFT);
|
||||||
|
}
|
||||||
|
if (this.renderBounds.height == 0) {
|
||||||
|
this.renderBounds.height = this.parent.getFramePointY(FramePoint.TOP)
|
||||||
|
- this.parent.getFramePointY(FramePoint.BOTTOM);
|
||||||
|
}
|
||||||
|
System.out.println(
|
||||||
|
getClass().getSimpleName() + ":" + this.name + " finishing position bounds: " + this.renderBounds);
|
||||||
|
innerPositionBounds(viewport);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract void innerPositionBounds(final Viewport viewport);
|
||||||
|
|
||||||
|
public boolean isVisible() {
|
||||||
|
return this.visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getLevel() {
|
||||||
|
return this.level;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setVisible(final boolean visible) {
|
||||||
|
this.visible = visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLevel(final int level) {
|
||||||
|
this.level = level;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,36 @@
|
|||||||
|
package com.etheller.warsmash.parsers.fdf.frames;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
|
||||||
|
import com.badlogic.gdx.utils.viewport.Viewport;
|
||||||
|
|
||||||
|
public abstract class AbstractUIFrame extends AbstractRenderableFrame implements UIFrame {
|
||||||
|
private final List<UIFrame> childFrames = new ArrayList<>();
|
||||||
|
|
||||||
|
public void add(final UIFrame childFrame) {
|
||||||
|
if (childFrame == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.childFrames.add(childFrame);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AbstractUIFrame(final String name, final UIFrame parent) {
|
||||||
|
super(name, parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void render(final SpriteBatch batch) {
|
||||||
|
for (final UIFrame childFrame : this.childFrames) {
|
||||||
|
childFrame.render(batch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void innerPositionBounds(final Viewport viewport) {
|
||||||
|
for (final UIFrame childFrame : this.childFrames) {
|
||||||
|
childFrame.positionBounds(viewport);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
package com.etheller.warsmash.parsers.fdf.frames;
|
||||||
|
|
||||||
|
public class SimpleFrame extends AbstractUIFrame {
|
||||||
|
|
||||||
|
public SimpleFrame(final String name, final UIFrame parent) {
|
||||||
|
super(name, parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
package com.etheller.warsmash.parsers.fdf.frames;
|
||||||
|
|
||||||
|
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
|
||||||
|
import com.badlogic.gdx.graphics.g2d.TextureRegion;
|
||||||
|
import com.badlogic.gdx.utils.viewport.Viewport;
|
||||||
|
|
||||||
|
public class TextureFrame extends AbstractRenderableFrame {
|
||||||
|
private final TextureRegion texture;
|
||||||
|
|
||||||
|
public TextureFrame(final String name, final UIFrame parent, final TextureRegion texture) {
|
||||||
|
super(name, parent);
|
||||||
|
this.texture = texture;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void render(final SpriteBatch batch) {
|
||||||
|
batch.draw(this.texture, this.renderBounds.x, this.renderBounds.y, this.renderBounds.width,
|
||||||
|
this.renderBounds.height);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void innerPositionBounds(final Viewport viewport) {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,22 @@
|
|||||||
|
package com.etheller.warsmash.parsers.fdf.frames;
|
||||||
|
|
||||||
|
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
|
||||||
|
import com.badlogic.gdx.utils.viewport.Viewport;
|
||||||
|
import com.etheller.warsmash.parsers.fdf.datamodel.AnchorDefinition;
|
||||||
|
import com.etheller.warsmash.parsers.fdf.datamodel.FramePoint;
|
||||||
|
|
||||||
|
public interface UIFrame {
|
||||||
|
public void render(SpriteBatch batch);
|
||||||
|
|
||||||
|
public float getFramePointX(FramePoint framePoint);
|
||||||
|
|
||||||
|
public float getFramePointY(FramePoint framePoint);
|
||||||
|
|
||||||
|
void positionBounds(final Viewport viewport);
|
||||||
|
|
||||||
|
void addAnchor(final AnchorDefinition anchorDefinition);
|
||||||
|
|
||||||
|
void setWidth(final float width);
|
||||||
|
|
||||||
|
void setHeight(final float height);
|
||||||
|
}
|
64
core/src/com/etheller/warsmash/parsers/jass/JassTest.java
Normal file
64
core/src/com/etheller/warsmash/parsers/jass/JassTest.java
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
package com.etheller.warsmash.parsers.jass;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import org.antlr.v4.runtime.BaseErrorListener;
|
||||||
|
import org.antlr.v4.runtime.CharStreams;
|
||||||
|
import org.antlr.v4.runtime.CommonTokenStream;
|
||||||
|
import org.antlr.v4.runtime.RecognitionException;
|
||||||
|
import org.antlr.v4.runtime.Recognizer;
|
||||||
|
|
||||||
|
import com.etheller.interpreter.JassLexer;
|
||||||
|
import com.etheller.interpreter.JassParser;
|
||||||
|
import com.etheller.interpreter.ast.visitors.JassProgramVisitor;
|
||||||
|
import com.etheller.warsmash.datasources.CompoundDataSourceDescriptor;
|
||||||
|
import com.etheller.warsmash.datasources.DataSource;
|
||||||
|
import com.etheller.warsmash.datasources.DataSourceDescriptor;
|
||||||
|
import com.etheller.warsmash.datasources.FolderDataSourceDescriptor;
|
||||||
|
|
||||||
|
public class JassTest {
|
||||||
|
public static final boolean REPORT_SYNTAX_ERRORS = true;
|
||||||
|
|
||||||
|
public static void main(final String[] args) {
|
||||||
|
final JassProgramVisitor jassProgramVisitor = new JassProgramVisitor();
|
||||||
|
try {
|
||||||
|
final FolderDataSourceDescriptor war3mpq = new FolderDataSourceDescriptor(
|
||||||
|
"E:\\Backups\\Warcraft\\Data\\127");
|
||||||
|
final FolderDataSourceDescriptor testingFolder = new FolderDataSourceDescriptor(
|
||||||
|
"E:\\Backups\\Warsmash\\Data");
|
||||||
|
final FolderDataSourceDescriptor currentFolder = new FolderDataSourceDescriptor(".");
|
||||||
|
final DataSource dataSource = new CompoundDataSourceDescriptor(
|
||||||
|
Arrays.<DataSourceDescriptor>asList(war3mpq, testingFolder, currentFolder)).createDataSource();
|
||||||
|
JassLexer lexer;
|
||||||
|
try {
|
||||||
|
lexer = new JassLexer(CharStreams.fromStream(dataSource.getResourceAsStream("Scripts\\common.j")));
|
||||||
|
}
|
||||||
|
catch (final IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
final JassParser parser = new JassParser(new CommonTokenStream(lexer));
|
||||||
|
parser.addErrorListener(new BaseErrorListener() {
|
||||||
|
@Override
|
||||||
|
public void syntaxError(final Recognizer<?, ?> recognizer, final Object offendingSymbol, final int line,
|
||||||
|
final int charPositionInLine, final String msg, final RecognitionException e) {
|
||||||
|
if (!REPORT_SYNTAX_ERRORS) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String sourceName = recognizer.getInputStream().getSourceName();
|
||||||
|
if (!sourceName.isEmpty()) {
|
||||||
|
sourceName = String.format("%s:%d:%d: ", sourceName, line, charPositionInLine);
|
||||||
|
}
|
||||||
|
|
||||||
|
System.err.println(sourceName + "line " + line + ":" + charPositionInLine + " " + msg);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
jassProgramVisitor.visit(parser.program());
|
||||||
|
}
|
||||||
|
catch (final Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -11,16 +11,16 @@ import java.util.LinkedHashMap;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import com.etheller.warsmash.util.WorldEditStrings;
|
import com.etheller.warsmash.util.StringBundle;
|
||||||
|
|
||||||
public class DataTable implements ObjectData {
|
public class DataTable implements ObjectData {
|
||||||
private static final boolean DEBUG = false;
|
private static final boolean DEBUG = false;
|
||||||
|
|
||||||
Map<StringKey, Element> dataTable = new LinkedHashMap<>();
|
Map<StringKey, Element> dataTable = new LinkedHashMap<>();
|
||||||
|
|
||||||
private final WorldEditStrings worldEditStrings;
|
private final StringBundle worldEditStrings;
|
||||||
|
|
||||||
public DataTable(final WorldEditStrings worldEditStrings) {
|
public DataTable(final StringBundle worldEditStrings) {
|
||||||
this.worldEditStrings = worldEditStrings;
|
this.worldEditStrings = worldEditStrings;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -219,10 +219,10 @@ public enum RenderMathUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void unpackPlanes(final Vector4[] planes, final Matrix4 m) {
|
public static void unpackPlanes(final Vector4[] planes, final Matrix4 m) {
|
||||||
final float a00 = m.val[Matrix4.M00], a01 = m.val[Matrix4.M10], a02 = m.val[Matrix4.M20],
|
final float a00 = m.val[Matrix4.M00], a01 = m.val[Matrix4.M01], a02 = m.val[Matrix4.M02],
|
||||||
a03 = m.val[Matrix4.M30], a10 = m.val[Matrix4.M01], a11 = m.val[Matrix4.M11], a12 = m.val[Matrix4.M21],
|
a03 = m.val[Matrix4.M03], a10 = m.val[Matrix4.M10], a11 = m.val[Matrix4.M11], a12 = m.val[Matrix4.M12],
|
||||||
a13 = m.val[Matrix4.M31], a20 = m.val[Matrix4.M02], a21 = m.val[Matrix4.M12], a22 = m.val[Matrix4.M22],
|
a13 = m.val[Matrix4.M13], a20 = m.val[Matrix4.M20], a21 = m.val[Matrix4.M21], a22 = m.val[Matrix4.M22],
|
||||||
a23 = m.val[Matrix4.M32], a30 = m.val[Matrix4.M03], a31 = m.val[Matrix4.M13], a32 = m.val[Matrix4.M23],
|
a23 = m.val[Matrix4.M23], a30 = m.val[Matrix4.M30], a31 = m.val[Matrix4.M31], a32 = m.val[Matrix4.M32],
|
||||||
a33 = m.val[Matrix4.M33];
|
a33 = m.val[Matrix4.M33];
|
||||||
|
|
||||||
// Left clipping plane
|
// Left clipping plane
|
||||||
@ -293,7 +293,7 @@ public enum RenderMathUtils {
|
|||||||
public static Vector3 unproject(final Vector3 out, final Vector3 v, final Matrix4 inverseMatrix,
|
public static Vector3 unproject(final Vector3 out, final Vector3 v, final Matrix4 inverseMatrix,
|
||||||
final Rectangle viewport) {
|
final Rectangle viewport) {
|
||||||
final float x = ((2 * (v.x - viewport.x)) / viewport.width) - 1;
|
final float x = ((2 * (v.x - viewport.x)) / viewport.width) - 1;
|
||||||
final float y = 1 - ((2 * (v.y - viewport.y)) / viewport.height);
|
final float y = ((2 * (v.y - viewport.y)) / viewport.height) - 1;
|
||||||
final float z = (2 * v.z) - 1;
|
final float z = (2 * v.z) - 1;
|
||||||
|
|
||||||
heap.set(x, y, z, 1);
|
heap.set(x, y, z, 1);
|
||||||
@ -481,6 +481,23 @@ public enum RenderMathUtils {
|
|||||||
return wrapper;
|
return wrapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static IntBuffer wrap(final int[] positions) {
|
||||||
|
final IntBuffer wrapper = ByteBuffer.allocateDirect(positions.length * 4).order(ByteOrder.nativeOrder())
|
||||||
|
.asIntBuffer();
|
||||||
|
wrapper.put(positions);
|
||||||
|
wrapper.clear();
|
||||||
|
return wrapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ByteBuffer wrapAsBytes(final int[] positions) {
|
||||||
|
final ByteBuffer wrapper = ByteBuffer.allocateDirect(positions.length).order(ByteOrder.nativeOrder());
|
||||||
|
for (final int face : positions) {
|
||||||
|
wrapper.put((byte) face);
|
||||||
|
}
|
||||||
|
wrapper.clear();
|
||||||
|
return wrapper;
|
||||||
|
}
|
||||||
|
|
||||||
public static Buffer wrap(final short[] cornerTextures) {
|
public static Buffer wrap(final short[] cornerTextures) {
|
||||||
final ByteBuffer wrapper = ByteBuffer.allocateDirect(cornerTextures.length).order(ByteOrder.nativeOrder());
|
final ByteBuffer wrapper = ByteBuffer.allocateDirect(cornerTextures.length).order(ByteOrder.nativeOrder());
|
||||||
for (final short face : cornerTextures) {
|
for (final short face : cornerTextures) {
|
||||||
|
19
core/src/com/etheller/warsmash/util/StringBundle.java
Normal file
19
core/src/com/etheller/warsmash/util/StringBundle.java
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
package com.etheller.warsmash.util;
|
||||||
|
|
||||||
|
public interface StringBundle {
|
||||||
|
String getString(String string);
|
||||||
|
|
||||||
|
String getStringCaseSensitive(final String key);
|
||||||
|
|
||||||
|
StringBundle EMPTY = new StringBundle() {
|
||||||
|
@Override
|
||||||
|
public String getStringCaseSensitive(final String key) {
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getString(final String string) {
|
||||||
|
return string;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
@ -9,7 +9,7 @@ import java.util.ResourceBundle;
|
|||||||
|
|
||||||
import com.etheller.warsmash.datasources.DataSource;
|
import com.etheller.warsmash.datasources.DataSource;
|
||||||
|
|
||||||
public class WorldEditStrings {
|
public class WorldEditStrings implements StringBundle {
|
||||||
private ResourceBundle bundle;
|
private ResourceBundle bundle;
|
||||||
private ResourceBundle bundlegs;
|
private ResourceBundle bundlegs;
|
||||||
|
|
||||||
@ -30,6 +30,7 @@ public class WorldEditStrings {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public String getString(String string) {
|
public String getString(String string) {
|
||||||
try {
|
try {
|
||||||
while (string.toUpperCase().startsWith("WESTRING")) {
|
while (string.toUpperCase().startsWith("WESTRING")) {
|
||||||
@ -60,6 +61,7 @@ public class WorldEditStrings {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public String getStringCaseSensitive(final String key) {
|
public String getStringCaseSensitive(final String key) {
|
||||||
try {
|
try {
|
||||||
return this.bundle.getString(key);
|
return this.bundle.getString(key);
|
||||||
|
@ -72,10 +72,10 @@ public class Grid {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void moved(final ModelInstance instance) {
|
public void moved(final ModelInstance instance, final float upcomingX, final float upcomingY) {
|
||||||
final Bounds bounds = instance.model.bounds;
|
final Bounds bounds = instance.model.bounds;
|
||||||
final float x = (instance.worldLocation.x + bounds.x) - this.x;
|
final float x = (upcomingX + bounds.x) - this.x;
|
||||||
final float y = (instance.worldLocation.y + bounds.y) - this.y;
|
final float y = (upcomingY + bounds.y) - this.y;
|
||||||
final float r = bounds.r;
|
final float r = bounds.r;
|
||||||
final Vector3 s = instance.worldScale;
|
final Vector3 s = instance.worldScale;
|
||||||
int left = (int) (Math.floor((x - (r * s.x)) / this.cellWidth));
|
int left = (int) (Math.floor((x - (r * s.x)) / this.cellWidth));
|
||||||
|
@ -40,6 +40,7 @@ public class GridCell {
|
|||||||
if (true) {
|
if (true) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.plane = RenderMathUtils.testCell(camera.planes, this.left, this.right, this.bottom, this.top, this.plane);
|
this.plane = RenderMathUtils.testCell(camera.planes, this.left, this.right, this.bottom, this.top, this.plane);
|
||||||
|
|
||||||
return this.plane == -1;
|
return this.plane == -1;
|
||||||
|
@ -89,17 +89,31 @@ public abstract class ModelInstance extends Node {
|
|||||||
super.recalculateTransformation();
|
super.recalculateTransformation();
|
||||||
|
|
||||||
if (this.scene != null) {
|
if (this.scene != null) {
|
||||||
this.scene.grid.moved(this);
|
this.scene.grid.moved(this, this.worldLocation.x, this.worldLocation.y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isVisible(final Camera camera) {
|
public boolean isVisible(final Camera camera) {
|
||||||
if (true) {
|
// can't just use world location if it moves
|
||||||
return true;
|
float x, y, z;
|
||||||
|
if (this.dirty) {
|
||||||
|
// TODO this is an incorrect, predicted location for dirty case
|
||||||
|
if ((this.parent != null) && !this.dontInheritTranslation) {
|
||||||
|
x = this.parent.localLocation.x + this.localLocation.x;
|
||||||
|
y = this.parent.localLocation.y + this.localLocation.y;
|
||||||
|
z = this.parent.localLocation.z + this.localLocation.z;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
x = this.localLocation.x;
|
||||||
|
y = this.localLocation.y;
|
||||||
|
z = this.localLocation.z;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
x = this.worldLocation.x;
|
||||||
|
y = this.worldLocation.y;
|
||||||
|
z = this.worldLocation.z;
|
||||||
}
|
}
|
||||||
final float x = this.worldLocation.x;
|
|
||||||
final float y = this.worldLocation.y;
|
|
||||||
final float z = this.worldLocation.z;
|
|
||||||
final Bounds bounds = this.model.bounds;
|
final Bounds bounds = this.model.bounds;
|
||||||
final Vector4[] planes = camera.planes;
|
final Vector4[] planes = camera.planes;
|
||||||
|
|
||||||
|
@ -31,21 +31,18 @@ import com.etheller.warsmash.viewer5.handlers.w3x.DynamicShadowManager;
|
|||||||
* audio is always on in LibGDX generally. So we will probably simplify or skip
|
* audio is always on in LibGDX generally. So we will probably simplify or skip
|
||||||
* over those behaviors other than a boolean on/off toggle for audio.
|
* over those behaviors other than a boolean on/off toggle for audio.
|
||||||
*/
|
*/
|
||||||
public class Scene {
|
public abstract class Scene {
|
||||||
|
|
||||||
public final ModelViewer viewer;
|
public final ModelViewer viewer;
|
||||||
public final Camera camera;
|
public final Camera camera;
|
||||||
public Grid grid;
|
|
||||||
public int visibleCells;
|
|
||||||
public int visibleInstances;
|
|
||||||
public int updatedParticles;
|
public int updatedParticles;
|
||||||
public boolean audioEnabled;
|
public boolean audioEnabled;
|
||||||
public AudioContext audioContext;
|
public AudioContext audioContext;
|
||||||
|
|
||||||
public final List<ModelInstance> instances;
|
public final List<ModelInstance> instances;
|
||||||
public final int currentInstance;
|
public int currentInstance;
|
||||||
public final List<ModelInstance> batchedInstances;
|
public final List<ModelInstance> batchedInstances;
|
||||||
public final int currentBatchedInstance;
|
public int currentBatchedInstance;
|
||||||
public final EmittedObjectUpdater emitterObjectUpdater;
|
public final EmittedObjectUpdater emitterObjectUpdater;
|
||||||
public final Map<TextureMapper, RenderBatch> batches;
|
public final Map<TextureMapper, RenderBatch> batches;
|
||||||
public final Comparator<ModelInstance> instanceDepthComparator;
|
public final Comparator<ModelInstance> instanceDepthComparator;
|
||||||
@ -64,10 +61,7 @@ public class Scene {
|
|||||||
final CanvasProvider canvas = viewer.canvas;
|
final CanvasProvider canvas = viewer.canvas;
|
||||||
this.viewer = viewer;
|
this.viewer = viewer;
|
||||||
this.camera = new Camera();
|
this.camera = new Camera();
|
||||||
this.grid = new Grid(-100000, -100000, 200000, 200000, 200000, 200000);
|
|
||||||
|
|
||||||
this.visibleCells = 0;
|
|
||||||
this.visibleInstances = 0;
|
|
||||||
this.updatedParticles = 0;
|
this.updatedParticles = 0;
|
||||||
|
|
||||||
this.audioEnabled = false;
|
this.audioEnabled = false;
|
||||||
@ -117,8 +111,7 @@ public class Scene {
|
|||||||
|
|
||||||
// Only allow instances that are actually ok to be added the scene.
|
// Only allow instances that are actually ok to be added the scene.
|
||||||
if (instance.model.ok) {
|
if (instance.model.ok) {
|
||||||
this.grid.moved(instance);
|
instanceMoved(instance, instance.worldLocation.x, instance.worldLocation.y);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -126,9 +119,11 @@ public class Scene {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public abstract void instanceMoved(ModelInstance instance, float x, float y);
|
||||||
|
|
||||||
public boolean removeInstance(final ModelInstance instance) {
|
public boolean removeInstance(final ModelInstance instance) {
|
||||||
if (instance.scene == this) {
|
if (instance.scene == this) {
|
||||||
this.grid.remove(instance);
|
innerRemove(instance);
|
||||||
|
|
||||||
instance.scene = null;
|
instance.scene = null;
|
||||||
this.instances.remove(instance);
|
this.instances.remove(instance);
|
||||||
@ -138,17 +133,9 @@ public class Scene {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void clear() {
|
protected abstract void innerRemove(ModelInstance instance);
|
||||||
// First remove references to this scene stored in the instances.
|
|
||||||
for (final GridCell cell : this.grid.cells) {
|
|
||||||
for (final ModelInstance instance : cell.instances) {
|
|
||||||
instance.scene = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Then remove references to the instances.
|
public abstract void clear();
|
||||||
this.grid.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean detach() {
|
public boolean detach() {
|
||||||
if (this.viewer != null) {
|
if (this.viewer != null) {
|
||||||
@ -191,54 +178,10 @@ public class Scene {
|
|||||||
|
|
||||||
final int frame = this.viewer.frame;
|
final int frame = this.viewer.frame;
|
||||||
|
|
||||||
int currentInstance = 0;
|
final int currentInstance = 0;
|
||||||
int currentBatchedInstance = 0;
|
final int currentBatchedInstance = 0;
|
||||||
|
|
||||||
this.visibleCells = 0;
|
innerUpdate(dt, frame);
|
||||||
this.visibleInstances = 0;
|
|
||||||
|
|
||||||
// Update and collect all of the visible instances.
|
|
||||||
for (final GridCell cell : this.grid.cells) {
|
|
||||||
if (cell.isVisible(this.camera)) {
|
|
||||||
this.visibleCells += 1;
|
|
||||||
|
|
||||||
for (final ModelInstance instance : new ArrayList<>(cell.instances)) {
|
|
||||||
// final ModelInstance instance = cell.instances.get(i);
|
|
||||||
if (instance.rendered && (instance.cullFrame < frame) && instance.isVisible(this.camera)) {
|
|
||||||
instance.cullFrame = frame;
|
|
||||||
|
|
||||||
if (instance.updateFrame < frame) {
|
|
||||||
instance.update(dt, this);
|
|
||||||
if (!instance.rendered) {
|
|
||||||
// it became hidden while it updated
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (instance.isBatched()) {
|
|
||||||
if (currentBatchedInstance < this.batchedInstances.size()) {
|
|
||||||
this.batchedInstances.set(currentBatchedInstance++, instance);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this.batchedInstances.add(instance);
|
|
||||||
currentBatchedInstance++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (currentInstance < this.instances.size()) {
|
|
||||||
this.instances.set(currentInstance++, instance);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this.instances.add(instance);
|
|
||||||
currentInstance++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.visibleInstances += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = this.batchedInstances.size() - 1; i >= currentBatchedInstance; i--) {
|
for (int i = this.batchedInstances.size() - 1; i >= currentBatchedInstance; i--) {
|
||||||
this.batchedInstances.remove(i);
|
this.batchedInstances.remove(i);
|
||||||
@ -253,6 +196,8 @@ public class Scene {
|
|||||||
this.updatedParticles = this.emitterObjectUpdater.objects.size();
|
this.updatedParticles = this.emitterObjectUpdater.objects.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected abstract void innerUpdate(float dt, int frame);
|
||||||
|
|
||||||
public void startFrame() {
|
public void startFrame() {
|
||||||
final GL20 gl = this.viewer.gl;
|
final GL20 gl = this.viewer.gl;
|
||||||
final Rectangle viewport = this.camera.rect;
|
final Rectangle viewport = this.camera.rect;
|
||||||
|
73
core/src/com/etheller/warsmash/viewer5/SimpleScene.java
Normal file
73
core/src/com/etheller/warsmash/viewer5/SimpleScene.java
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
package com.etheller.warsmash.viewer5;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class SimpleScene extends Scene {
|
||||||
|
private final List<ModelInstance> allInstances = new ArrayList<>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void instanceMoved(final ModelInstance instance, final float x, final float y) {
|
||||||
|
if (instance.left == -1) {
|
||||||
|
instance.left = 0;
|
||||||
|
this.allInstances.add(instance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void innerRemove(final ModelInstance instance) {
|
||||||
|
this.allInstances.remove(instance);
|
||||||
|
instance.left = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clear() {
|
||||||
|
for (final ModelInstance instance : this.allInstances) {
|
||||||
|
instance.scene = null;
|
||||||
|
}
|
||||||
|
this.allInstances.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void innerUpdate(final float dt, final int frame) {
|
||||||
|
|
||||||
|
// Update and collect all of the visible instances.
|
||||||
|
for (final ModelInstance instance : new ArrayList<>(this.allInstances)) {
|
||||||
|
// Below: current SimpleScene is not checking instance visibility.
|
||||||
|
// It's meant to be simple. Low number of models. Render everything.
|
||||||
|
// Otherwise unit portraits bust
|
||||||
|
if (instance.rendered && (instance.cullFrame < frame) && instance.isVisible(this.camera)) {
|
||||||
|
instance.cullFrame = frame;
|
||||||
|
|
||||||
|
if (instance.updateFrame < frame) {
|
||||||
|
instance.update(dt, this);
|
||||||
|
if (!instance.rendered) {
|
||||||
|
// it became hidden while it updated
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (instance.isBatched()) {
|
||||||
|
if (this.currentBatchedInstance < this.batchedInstances.size()) {
|
||||||
|
this.batchedInstances.set(this.currentBatchedInstance++, instance);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.batchedInstances.add(instance);
|
||||||
|
this.currentBatchedInstance++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (this.currentInstance < this.instances.size()) {
|
||||||
|
this.instances.set(this.currentInstance++, instance);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.instances.add(instance);
|
||||||
|
this.currentInstance++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
105
core/src/com/etheller/warsmash/viewer5/WorldScene.java
Normal file
105
core/src/com/etheller/warsmash/viewer5/WorldScene.java
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
package com.etheller.warsmash.viewer5;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A scene.
|
||||||
|
*
|
||||||
|
* Every scene has its own list of model instances, and its own camera and
|
||||||
|
* viewport.
|
||||||
|
*
|
||||||
|
* In addition, in Ghostwolf's original code every scene may have its own
|
||||||
|
* AudioContext if enableAudio() is called. If audo is enabled, the
|
||||||
|
* AudioContext's listener's location will be updated automatically. Note that
|
||||||
|
* due to browser policies, this may be done only after user interaction with
|
||||||
|
* the web page.
|
||||||
|
*
|
||||||
|
* In "Warsmash", we are starting from an attempt to replicate Ghostwolf, but
|
||||||
|
* audio is always on in LibGDX generally. So we will probably simplify or skip
|
||||||
|
* over those behaviors other than a boolean on/off toggle for audio.
|
||||||
|
*/
|
||||||
|
public class WorldScene extends Scene {
|
||||||
|
|
||||||
|
public Grid grid;
|
||||||
|
public int visibleCells;
|
||||||
|
public int visibleInstances;
|
||||||
|
|
||||||
|
public WorldScene(final ModelViewer viewer) {
|
||||||
|
super(viewer);
|
||||||
|
this.grid = new Grid(-100000, -100000, 200000, 200000, 200000, 200000);
|
||||||
|
this.visibleCells = 0;
|
||||||
|
this.visibleInstances = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void instanceMoved(final ModelInstance instance, final float x, final float y) {
|
||||||
|
this.grid.moved(instance, x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void innerRemove(final ModelInstance instance) {
|
||||||
|
this.grid.remove(instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clear() {
|
||||||
|
// First remove references to this scene stored in the instances.
|
||||||
|
for (final GridCell cell : this.grid.cells) {
|
||||||
|
for (final ModelInstance instance : cell.instances) {
|
||||||
|
instance.scene = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Then remove references to the instances.
|
||||||
|
this.grid.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void innerUpdate(final float dt, final int frame) {
|
||||||
|
this.visibleCells = 0;
|
||||||
|
this.visibleInstances = 0;
|
||||||
|
|
||||||
|
// Update and collect all of the visible instances.
|
||||||
|
for (final GridCell cell : this.grid.cells) {
|
||||||
|
if (cell.isVisible(this.camera)) {
|
||||||
|
this.visibleCells += 1;
|
||||||
|
|
||||||
|
for (final ModelInstance instance : new ArrayList<>(cell.instances)) {
|
||||||
|
// final ModelInstance instance = cell.instances.get(i);
|
||||||
|
if (instance.rendered && (instance.cullFrame < frame) && instance.isVisible(this.camera)) {
|
||||||
|
instance.cullFrame = frame;
|
||||||
|
|
||||||
|
if (instance.updateFrame < frame) {
|
||||||
|
instance.update(dt, this);
|
||||||
|
if (!instance.rendered) {
|
||||||
|
// it became hidden while it updated
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (instance.isBatched()) {
|
||||||
|
if (this.currentBatchedInstance < this.batchedInstances.size()) {
|
||||||
|
this.batchedInstances.set(this.currentBatchedInstance++, instance);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.batchedInstances.add(instance);
|
||||||
|
this.currentBatchedInstance++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (this.currentInstance < this.instances.size()) {
|
||||||
|
this.instances.set(this.currentInstance++, instance);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.instances.add(instance);
|
||||||
|
this.currentInstance++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.visibleInstances += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -21,9 +21,13 @@ public class Geoset {
|
|||||||
public boolean hasAlphaAnim;
|
public boolean hasAlphaAnim;
|
||||||
public boolean hasColorAnim;
|
public boolean hasColorAnim;
|
||||||
public boolean hasObjectAnim;
|
public boolean hasObjectAnim;
|
||||||
|
private final int openGLSkinType;
|
||||||
|
private final int skinStride;
|
||||||
|
private final int boneCountOffsetBytes;
|
||||||
|
|
||||||
public Geoset(final MdxModel model, final int index, final int positionOffset, final int normalOffset,
|
public Geoset(final MdxModel model, final int index, final int positionOffset, final int normalOffset,
|
||||||
final int uvOffset, final int skinOffset, final int faceOffset, final int vertices, final int elements) {
|
final int uvOffset, final int skinOffset, final int faceOffset, final int vertices, final int elements,
|
||||||
|
final int openGLSkinType, final int skinStride, final int boneCountOffsetBytes) {
|
||||||
this.model = model;
|
this.model = model;
|
||||||
this.index = index;
|
this.index = index;
|
||||||
this.positionOffset = positionOffset;
|
this.positionOffset = positionOffset;
|
||||||
@ -33,6 +37,9 @@ public class Geoset {
|
|||||||
this.faceOffset = faceOffset;
|
this.faceOffset = faceOffset;
|
||||||
this.vertices = vertices;
|
this.vertices = vertices;
|
||||||
this.elements = elements;
|
this.elements = elements;
|
||||||
|
this.openGLSkinType = openGLSkinType;
|
||||||
|
this.skinStride = skinStride;
|
||||||
|
this.boneCountOffsetBytes = boneCountOffsetBytes;
|
||||||
|
|
||||||
for (final GeosetAnimation geosetAnimation : model.getGeosetAnimations()) {
|
for (final GeosetAnimation geosetAnimation : model.getGeosetAnimations()) {
|
||||||
if (geosetAnimation.geosetId == index) {
|
if (geosetAnimation.geosetId == index) {
|
||||||
@ -96,8 +103,9 @@ public class Geoset {
|
|||||||
shader.setVertexAttribute("a_position", 3, GL20.GL_FLOAT, false, 0, this.positionOffset);
|
shader.setVertexAttribute("a_position", 3, GL20.GL_FLOAT, false, 0, this.positionOffset);
|
||||||
// shader.setVertexAttribute("a_normal", 3, GL20.GL_FLOAT, false, 0, this.normalOffset);
|
// shader.setVertexAttribute("a_normal", 3, GL20.GL_FLOAT, false, 0, this.normalOffset);
|
||||||
shader.setVertexAttribute("a_uv", 2, GL20.GL_FLOAT, false, 0, this.uvOffset + (coordId * this.vertices * 8));
|
shader.setVertexAttribute("a_uv", 2, GL20.GL_FLOAT, false, 0, this.uvOffset + (coordId * this.vertices * 8));
|
||||||
shader.setVertexAttribute("a_bones", 4, GL20.GL_UNSIGNED_BYTE, false, 5, this.skinOffset);
|
shader.setVertexAttribute("a_bones", 4, this.openGLSkinType, false, this.skinStride, this.skinOffset);
|
||||||
shader.setVertexAttribute("a_boneNumber", 1, GL20.GL_UNSIGNED_BYTE, false, 5, this.skinOffset + 4);
|
shader.setVertexAttribute("a_boneNumber", 1, this.openGLSkinType, false, this.skinStride,
|
||||||
|
this.skinOffset + this.boneCountOffsetBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void bindExtended(final ShaderProgram shader, final int coordId) {
|
public void bindExtended(final ShaderProgram shader, final int coordId) {
|
||||||
@ -105,9 +113,11 @@ public class Geoset {
|
|||||||
shader.setVertexAttribute("a_position", 3, GL20.GL_FLOAT, false, 0, this.positionOffset);
|
shader.setVertexAttribute("a_position", 3, GL20.GL_FLOAT, false, 0, this.positionOffset);
|
||||||
shader.setVertexAttribute("a_normal", 3, GL20.GL_FLOAT, false, 0, this.normalOffset);
|
shader.setVertexAttribute("a_normal", 3, GL20.GL_FLOAT, false, 0, this.normalOffset);
|
||||||
shader.setVertexAttribute("a_uv", 2, GL20.GL_FLOAT, false, 0, this.uvOffset + (coordId * this.vertices * 8));
|
shader.setVertexAttribute("a_uv", 2, GL20.GL_FLOAT, false, 0, this.uvOffset + (coordId * this.vertices * 8));
|
||||||
shader.setVertexAttribute("a_bones", 4, GL20.GL_UNSIGNED_BYTE, false, 9, this.skinOffset);
|
shader.setVertexAttribute("a_bones", 4, this.openGLSkinType, false, this.skinStride, this.skinOffset);
|
||||||
shader.setVertexAttribute("a_extendedBones", 4, GL20.GL_UNSIGNED_BYTE, false, 9, this.skinOffset + 4);
|
shader.setVertexAttribute("a_extendedBones", 4, this.openGLSkinType, false, this.skinStride,
|
||||||
shader.setVertexAttribute("a_boneNumber", 1, GL20.GL_UNSIGNED_BYTE, false, 9, this.skinOffset + 8);
|
this.skinOffset + (this.boneCountOffsetBytes / 2));
|
||||||
|
shader.setVertexAttribute("a_boneNumber", 1, this.openGLSkinType, false, this.skinStride,
|
||||||
|
this.skinOffset + this.boneCountOffsetBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void render() {
|
public void render() {
|
||||||
|
@ -58,7 +58,7 @@ public class MdxModel extends com.etheller.warsmash.viewer5.Model<MdxHandler> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ModelInstance createInstance(final int type) {
|
public ModelInstance createInstance(final int type) {
|
||||||
if (type == 1) {
|
if ((type == 1) && false) {
|
||||||
return new MdxSimpleInstance(this);
|
return new MdxSimpleInstance(this);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -176,7 +176,7 @@ public class MdxModel extends com.etheller.warsmash.viewer5.Model<MdxHandler> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Geosets
|
// Geosets
|
||||||
SetupGeosets.setupGeosets(this, parser.getGeosets());
|
SetupGeosets.setupGeosets(this, parser.getGeosets(), parser.getBones().size() >= 256);
|
||||||
|
|
||||||
this.pivotPoints = parser.getPivotPoints();
|
this.pivotPoints = parser.getPivotPoints();
|
||||||
|
|
||||||
@ -344,4 +344,8 @@ public class MdxModel extends com.etheller.warsmash.viewer5.Model<MdxHandler> {
|
|||||||
return this.eventObjects;
|
return this.eventObjects;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<Bone> getBones() {
|
||||||
|
return this.bones;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -12,8 +12,8 @@ public class SetupGeosets {
|
|||||||
private static final int EXTENDED_BATCH = 1;
|
private static final int EXTENDED_BATCH = 1;
|
||||||
private static final int REFORGED_BATCH = 2;
|
private static final int REFORGED_BATCH = 2;
|
||||||
|
|
||||||
public static void setupGeosets(final MdxModel model,
|
public static void setupGeosets(final MdxModel model, final List<com.etheller.warsmash.parsers.mdlx.Geoset> geosets,
|
||||||
final List<com.etheller.warsmash.parsers.mdlx.Geoset> geosets) {
|
final boolean bigNodeSpace) {
|
||||||
if (geosets.size() > 0) {
|
if (geosets.size() > 0) {
|
||||||
final GL20 gl = model.viewer.gl;
|
final GL20 gl = model.viewer.gl;
|
||||||
int positionBytes = 0;
|
int positionBytes = 0;
|
||||||
@ -23,6 +23,12 @@ public class SetupGeosets {
|
|||||||
int faceBytes = 0;
|
int faceBytes = 0;
|
||||||
final int[] batchTypes = new int[geosets.size()];
|
final int[] batchTypes = new int[geosets.size()];
|
||||||
|
|
||||||
|
final int extendedBatchStride = bigNodeSpace ? 36 : 9;
|
||||||
|
final int normalBatchStride = bigNodeSpace ? 20 : 5;
|
||||||
|
final int openGLSkinType = bigNodeSpace ? GL20.GL_UNSIGNED_INT : GL20.GL_UNSIGNED_BYTE;
|
||||||
|
final int normalBatchBoneCountOffsetBytes = bigNodeSpace ? 16 : 4;
|
||||||
|
final int extendedBatchBoneCountOffsetBytes = bigNodeSpace ? 32 : 8;
|
||||||
|
|
||||||
for (int i = 0, l = geosets.size(); i < l; i++) {
|
for (int i = 0, l = geosets.size(); i < l; i++) {
|
||||||
final com.etheller.warsmash.parsers.mdlx.Geoset geoset = geosets.get(i);
|
final com.etheller.warsmash.parsers.mdlx.Geoset geoset = geosets.get(i);
|
||||||
|
|
||||||
@ -48,12 +54,12 @@ public class SetupGeosets {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (biggestGroup > 4) {
|
if (biggestGroup > 4) {
|
||||||
skinBytes += vertices * 9;
|
skinBytes += vertices * extendedBatchStride;
|
||||||
|
|
||||||
batchTypes[i] = EXTENDED_BATCH;
|
batchTypes[i] = EXTENDED_BATCH;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
skinBytes += vertices * 5;
|
skinBytes += vertices * normalBatchStride;
|
||||||
|
|
||||||
batchTypes[i] = NORMAL_BATCH;
|
batchTypes[i] = NORMAL_BATCH;
|
||||||
}
|
}
|
||||||
@ -80,17 +86,31 @@ public class SetupGeosets {
|
|||||||
for (int i = 0, l = geosets.size(); i < l; i++) {
|
for (int i = 0, l = geosets.size(); i < l; i++) {
|
||||||
final com.etheller.warsmash.parsers.mdlx.Geoset geoset = geosets.get(i);
|
final com.etheller.warsmash.parsers.mdlx.Geoset geoset = geosets.get(i);
|
||||||
|
|
||||||
|
final int batchType = batchTypes[i];
|
||||||
if (true /* geoset.lod == 0 */) {
|
if (true /* geoset.lod == 0 */) {
|
||||||
final float[] positions = geoset.getVertices();
|
final float[] positions = geoset.getVertices();
|
||||||
final float[] normals = geoset.getNormals();
|
final float[] normals = geoset.getNormals();
|
||||||
final float[][] uvSets = geoset.getUvSets();
|
final float[][] uvSets = geoset.getUvSets();
|
||||||
final int[] faces = geoset.getFaces();
|
final int[] faces = geoset.getFaces();
|
||||||
byte[] skin = null;
|
int[] skin = null;
|
||||||
final int vertices = geoset.getVertices().length / 3;
|
final int vertices = geoset.getVertices().length / 3;
|
||||||
final int batchType = batchTypes[i];
|
|
||||||
|
int maxBones;
|
||||||
|
int skinStride;
|
||||||
|
int boneCountOffsetBytes;
|
||||||
|
if (batchType == EXTENDED_BATCH) {
|
||||||
|
maxBones = 8;
|
||||||
|
skinStride = extendedBatchStride;
|
||||||
|
boneCountOffsetBytes = extendedBatchBoneCountOffsetBytes;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
maxBones = 4;
|
||||||
|
skinStride = normalBatchStride;
|
||||||
|
boneCountOffsetBytes = normalBatchBoneCountOffsetBytes;
|
||||||
|
}
|
||||||
|
|
||||||
if (batchType == REFORGED_BATCH) {
|
if (batchType == REFORGED_BATCH) {
|
||||||
// skin = geoset.skin;
|
// skin = geoset.skin; // THIS IS NOT IMPLEMENTED
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
final long[] matrixIndices = geoset.getMatrixIndices();
|
final long[] matrixIndices = geoset.getMatrixIndices();
|
||||||
@ -102,12 +122,8 @@ public class SetupGeosets {
|
|||||||
// That being said, there are a few models with geosets that need more, for
|
// That being said, there are a few models with geosets that need more, for
|
||||||
// example the Water Elemental.
|
// example the Water Elemental.
|
||||||
// These geosets use a different shader, which support up to 8 bones per vertex.
|
// These geosets use a different shader, which support up to 8 bones per vertex.
|
||||||
int maxBones = 4;
|
|
||||||
if (batchType == EXTENDED_BATCH) {
|
|
||||||
maxBones = 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
skin = new byte[vertices * (maxBones + 1)];
|
skin = new int[vertices * (maxBones + 1)];
|
||||||
|
|
||||||
// Slice the matrix groups
|
// Slice the matrix groups
|
||||||
for (final long size : geoset.getMatrixGroups()) {
|
for (final long size : geoset.getMatrixGroups()) {
|
||||||
@ -130,17 +146,18 @@ public class SetupGeosets {
|
|||||||
final int bones = Math.min(matrixGroup.length, maxBones);
|
final int bones = Math.min(matrixGroup.length, maxBones);
|
||||||
|
|
||||||
for (int j = 0; j < bones; j++) {
|
for (int j = 0; j < bones; j++) {
|
||||||
skin[offset + j] = (byte) (matrixGroup[j] + 1); // 1 is added to diffrentiate
|
skin[offset + j] = (int) (matrixGroup[j] + 1); // 1 is added to diffrentiate
|
||||||
// between matrix 0, and no matrix.
|
// between matrix 0, and no matrix.
|
||||||
}
|
}
|
||||||
|
|
||||||
skin[offset + maxBones] = (byte) bones;
|
skin[offset + maxBones] = bones;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final Geoset vGeoset = new Geoset(model, model.getGeosets().size(), positionOffset, normalOffset,
|
final Geoset vGeoset = new Geoset(model, model.getGeosets().size(), positionOffset, normalOffset,
|
||||||
uvOffset, skinOffset, faceOffset, vertices, faces.length);
|
uvOffset, skinOffset, faceOffset, vertices, faces.length, openGLSkinType, skinStride,
|
||||||
|
boneCountOffsetBytes);
|
||||||
|
|
||||||
model.getGeosets().add(vGeoset);
|
model.getGeosets().add(vGeoset);
|
||||||
|
|
||||||
@ -173,8 +190,9 @@ public class SetupGeosets {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Skin.
|
// Skin.
|
||||||
gl.glBufferSubData(GL20.GL_ARRAY_BUFFER, skinOffset, skin.length, RenderMathUtils.wrap(skin));
|
gl.glBufferSubData(GL20.GL_ARRAY_BUFFER, skinOffset, skin.length,
|
||||||
skinOffset += skin.length * 1;
|
bigNodeSpace ? RenderMathUtils.wrap(skin) : RenderMathUtils.wrapAsBytes(skin));
|
||||||
|
skinOffset += skin.length * (bigNodeSpace ? 4 : 1);
|
||||||
|
|
||||||
// Faces.
|
// Faces.
|
||||||
gl.glBufferSubData(GL20.GL_ELEMENT_ARRAY_BUFFER, faceOffset, faces.length,
|
gl.glBufferSubData(GL20.GL_ELEMENT_ARRAY_BUFFER, faceOffset, faces.length,
|
||||||
|
@ -533,7 +533,7 @@ public class War3MapViewer extends ModelViewer {
|
|||||||
if (path.toLowerCase().endsWith(".mdl") || path.toLowerCase().endsWith(".mdx")) {
|
if (path.toLowerCase().endsWith(".mdl") || path.toLowerCase().endsWith(".mdx")) {
|
||||||
path = path.substring(0, path.length() - 4);
|
path = path.substring(0, path.length() - 4);
|
||||||
}
|
}
|
||||||
if (row.readSLKTagInt("fileVerFlags") == 2) {
|
if ((row.readSLKTagInt("fileVerFlags") == 2) && this.dataSource.has(path + "_V1.mdx")) {
|
||||||
path += "_V1";
|
path += "_V1";
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -804,6 +804,7 @@ public class War3MapViewer extends ModelViewer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public List<RenderUnit> selectUnit(final float x, final float y, final boolean toggle) {
|
public List<RenderUnit> selectUnit(final float x, final float y, final boolean toggle) {
|
||||||
|
System.out.println("world: " + x + "," + y);
|
||||||
final float[] ray = rayHeap;
|
final float[] ray = rayHeap;
|
||||||
mousePosHeap.set(x, y);
|
mousePosHeap.set(x, y);
|
||||||
this.worldScene.camera.screenToWorldRay(ray, mousePosHeap);
|
this.worldScene.camera.screenToWorldRay(ray, mousePosHeap);
|
||||||
|
@ -1025,10 +1025,14 @@ public class Terrain {
|
|||||||
final int shadowSize = columns * rows;
|
final int shadowSize = columns * rows;
|
||||||
final byte[] shadowData = new byte[columns * rows];
|
final byte[] shadowData = new byte[columns * rows];
|
||||||
if (this.viewer.mapMpq.has("war3map.shd")) {
|
if (this.viewer.mapMpq.has("war3map.shd")) {
|
||||||
final InputStream shadowSource = this.viewer.mapMpq.getResourceAsStream("war3map.shd");
|
final byte[] buffer;
|
||||||
final byte[] buffer = IOUtils.toByteArray(shadowSource);
|
|
||||||
|
try (final InputStream shadowSource = this.viewer.mapMpq.getResourceAsStream("war3map.shd")) {
|
||||||
|
buffer = IOUtils.toByteArray(shadowSource);
|
||||||
|
}
|
||||||
|
|
||||||
for (int i = 0; i < shadowSize; i++) {
|
for (int i = 0; i < shadowSize; i++) {
|
||||||
shadowData[i] = (byte) (buffer[i] / 2);
|
shadowData[i] = (byte) ((buffer[i] & 0xFF) / 2f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,7 +102,7 @@ public class RenderAttackProjectile {
|
|||||||
this.modelInstance.setLocation(this.x, this.y, this.z);
|
this.modelInstance.setLocation(this.x, this.y, this.z);
|
||||||
this.modelInstance.localRotation.setFromAxisRad(0, 0, 1, this.yaw);
|
this.modelInstance.localRotation.setFromAxisRad(0, 0, 1, this.yaw);
|
||||||
this.modelInstance.rotate(pitchHeap.setFromAxisRad(0, -1, 0, this.pitch));
|
this.modelInstance.rotate(pitchHeap.setFromAxisRad(0, -1, 0, this.pitch));
|
||||||
war3MapViewer.worldScene.grid.moved(this.modelInstance);
|
war3MapViewer.worldScene.grid.moved(this.modelInstance, this.x, this.y);
|
||||||
|
|
||||||
final boolean everythingDone = this.simulationProjectile.isDone() && this.modelInstance.sequenceEnded;
|
final boolean everythingDone = this.simulationProjectile.isDone() && this.modelInstance.sequenceEnded;
|
||||||
if (everythingDone) {
|
if (everythingDone) {
|
||||||
|
@ -176,7 +176,7 @@ public class RenderUnit {
|
|||||||
}
|
}
|
||||||
this.facing = (((this.facing + angleToAdd) % 360) + 360) % 360;
|
this.facing = (((this.facing + angleToAdd) % 360) + 360) % 360;
|
||||||
this.instance.setLocalRotation(tempQuat.setFromAxis(RenderMathUtils.VEC3_UNIT_Z, this.facing));
|
this.instance.setLocalRotation(tempQuat.setFromAxis(RenderMathUtils.VEC3_UNIT_Z, this.facing));
|
||||||
map.worldScene.grid.moved(this.instance);
|
map.worldScene.grid.moved(this.instance, this.location[0], this.location[1]);
|
||||||
final MdxComplexInstance mdxComplexInstance = this.instance;
|
final MdxComplexInstance mdxComplexInstance = this.instance;
|
||||||
final COrder currentOrder = this.simulationUnit.getCurrentOrder();
|
final COrder currentOrder = this.simulationUnit.getCurrentOrder();
|
||||||
if (this.simulationUnit.getLife() <= 0) {
|
if (this.simulationUnit.getLife() <= 0) {
|
||||||
|
1
fdfparser/.gitignore
vendored
Normal file
1
fdfparser/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/build/
|
@ -22,4 +22,9 @@ public class AnchorDefinition {
|
|||||||
public float getY() {
|
public float getY() {
|
||||||
return this.y;
|
return this.y;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "AnchorDefinition [myPoint=" + this.myPoint + ", x=" + this.x + ", y=" + this.y + "]";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,9 @@ import java.util.Map;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import com.etheller.warsmash.parsers.fdf.datamodel.fields.FrameDefinitionField;
|
import com.etheller.warsmash.parsers.fdf.datamodel.fields.FrameDefinitionField;
|
||||||
|
import com.etheller.warsmash.parsers.fdf.datamodel.fields.visitor.GetFloatFieldVisitor;
|
||||||
|
import com.etheller.warsmash.parsers.fdf.datamodel.fields.visitor.GetStringFieldVisitor;
|
||||||
|
import com.etheller.warsmash.parsers.fdf.datamodel.fields.visitor.GetVector4FieldVisitor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pretty sure this is probably not how it works in-game but this silly
|
* Pretty sure this is probably not how it works in-game but this silly
|
||||||
@ -58,6 +61,14 @@ public class FrameDefinition {
|
|||||||
this.flags.add(flag);
|
this.flags.add(flag);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean has(final String flag) {
|
||||||
|
return this.flags.contains(flag);
|
||||||
|
}
|
||||||
|
|
||||||
|
public FrameDefinitionField get(final String fieldName) {
|
||||||
|
return this.nameToField.get(fieldName);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "FrameDefinition [frameClass=" + this.frameClass + ", frameType=" + this.frameType + ", name="
|
return "FrameDefinition [frameClass=" + this.frameClass + ", frameType=" + this.frameType + ", name="
|
||||||
@ -65,4 +76,51 @@ public class FrameDefinition {
|
|||||||
+ this.nameToField + ", setPoints=" + this.setPoints + ", anchors=" + this.anchors + "]";
|
+ this.nameToField + ", setPoints=" + this.setPoints + ", anchors=" + this.anchors + "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getFrameType() {
|
||||||
|
return this.frameType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return this.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public FrameClass getFrameClass() {
|
||||||
|
return this.frameClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<FrameDefinition> getInnerFrames() {
|
||||||
|
return this.innerFrames;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<AnchorDefinition> getAnchors() {
|
||||||
|
return this.anchors;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<SetPointDefinition> getSetPoints() {
|
||||||
|
return this.setPoints;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getString(final String id) {
|
||||||
|
final FrameDefinitionField frameDefinitionField = this.nameToField.get(id);
|
||||||
|
if (frameDefinitionField != null) {
|
||||||
|
return frameDefinitionField.visit(GetStringFieldVisitor.INSTANCE);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Float getFloat(final String id) {
|
||||||
|
final FrameDefinitionField frameDefinitionField = this.nameToField.get(id);
|
||||||
|
if (frameDefinitionField != null) {
|
||||||
|
return frameDefinitionField.visit(GetFloatFieldVisitor.INSTANCE);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector4Definition getVector4(final String id) {
|
||||||
|
final FrameDefinitionField frameDefinitionField = this.nameToField.get(id);
|
||||||
|
if (frameDefinitionField != null) {
|
||||||
|
return frameDefinitionField.visit(GetVector4FieldVisitor.INSTANCE);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,56 @@
|
|||||||
|
package com.etheller.warsmash.parsers.fdf.datamodel.fields.visitor;
|
||||||
|
|
||||||
|
import com.etheller.warsmash.parsers.fdf.datamodel.fields.FloatFrameDefinitionField;
|
||||||
|
import com.etheller.warsmash.parsers.fdf.datamodel.fields.FontFrameDefinitionField;
|
||||||
|
import com.etheller.warsmash.parsers.fdf.datamodel.fields.FrameDefinitionFieldVisitor;
|
||||||
|
import com.etheller.warsmash.parsers.fdf.datamodel.fields.StringFrameDefinitionField;
|
||||||
|
import com.etheller.warsmash.parsers.fdf.datamodel.fields.StringPairFrameDefinitionField;
|
||||||
|
import com.etheller.warsmash.parsers.fdf.datamodel.fields.TextJustifyFrameDefinitionField;
|
||||||
|
import com.etheller.warsmash.parsers.fdf.datamodel.fields.Vector2FrameDefinitionField;
|
||||||
|
import com.etheller.warsmash.parsers.fdf.datamodel.fields.Vector3FrameDefinitionField;
|
||||||
|
import com.etheller.warsmash.parsers.fdf.datamodel.fields.Vector4FrameDefinitionField;
|
||||||
|
|
||||||
|
public class GetFloatFieldVisitor implements FrameDefinitionFieldVisitor<Float> {
|
||||||
|
public static GetFloatFieldVisitor INSTANCE = new GetFloatFieldVisitor();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Float accept(final StringFrameDefinitionField field) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Float accept(final StringPairFrameDefinitionField field) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Float accept(final FloatFrameDefinitionField field) {
|
||||||
|
return field.getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Float accept(final Vector3FrameDefinitionField field) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Float accept(final Vector4FrameDefinitionField field) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Float accept(final Vector2FrameDefinitionField field) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Float accept(final FontFrameDefinitionField field) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Float accept(final TextJustifyFrameDefinitionField field) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,56 @@
|
|||||||
|
package com.etheller.warsmash.parsers.fdf.datamodel.fields.visitor;
|
||||||
|
|
||||||
|
import com.etheller.warsmash.parsers.fdf.datamodel.fields.FloatFrameDefinitionField;
|
||||||
|
import com.etheller.warsmash.parsers.fdf.datamodel.fields.FontFrameDefinitionField;
|
||||||
|
import com.etheller.warsmash.parsers.fdf.datamodel.fields.FrameDefinitionFieldVisitor;
|
||||||
|
import com.etheller.warsmash.parsers.fdf.datamodel.fields.StringFrameDefinitionField;
|
||||||
|
import com.etheller.warsmash.parsers.fdf.datamodel.fields.StringPairFrameDefinitionField;
|
||||||
|
import com.etheller.warsmash.parsers.fdf.datamodel.fields.TextJustifyFrameDefinitionField;
|
||||||
|
import com.etheller.warsmash.parsers.fdf.datamodel.fields.Vector2FrameDefinitionField;
|
||||||
|
import com.etheller.warsmash.parsers.fdf.datamodel.fields.Vector3FrameDefinitionField;
|
||||||
|
import com.etheller.warsmash.parsers.fdf.datamodel.fields.Vector4FrameDefinitionField;
|
||||||
|
|
||||||
|
public class GetStringFieldVisitor implements FrameDefinitionFieldVisitor<String> {
|
||||||
|
public static GetStringFieldVisitor INSTANCE = new GetStringFieldVisitor();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String accept(final StringFrameDefinitionField field) {
|
||||||
|
return field.getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String accept(final StringPairFrameDefinitionField field) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String accept(final FloatFrameDefinitionField field) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String accept(final Vector3FrameDefinitionField field) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String accept(final Vector4FrameDefinitionField field) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String accept(final Vector2FrameDefinitionField field) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String accept(final FontFrameDefinitionField field) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String accept(final TextJustifyFrameDefinitionField field) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,57 @@
|
|||||||
|
package com.etheller.warsmash.parsers.fdf.datamodel.fields.visitor;
|
||||||
|
|
||||||
|
import com.etheller.warsmash.parsers.fdf.datamodel.Vector4Definition;
|
||||||
|
import com.etheller.warsmash.parsers.fdf.datamodel.fields.FloatFrameDefinitionField;
|
||||||
|
import com.etheller.warsmash.parsers.fdf.datamodel.fields.FontFrameDefinitionField;
|
||||||
|
import com.etheller.warsmash.parsers.fdf.datamodel.fields.FrameDefinitionFieldVisitor;
|
||||||
|
import com.etheller.warsmash.parsers.fdf.datamodel.fields.StringFrameDefinitionField;
|
||||||
|
import com.etheller.warsmash.parsers.fdf.datamodel.fields.StringPairFrameDefinitionField;
|
||||||
|
import com.etheller.warsmash.parsers.fdf.datamodel.fields.TextJustifyFrameDefinitionField;
|
||||||
|
import com.etheller.warsmash.parsers.fdf.datamodel.fields.Vector2FrameDefinitionField;
|
||||||
|
import com.etheller.warsmash.parsers.fdf.datamodel.fields.Vector3FrameDefinitionField;
|
||||||
|
import com.etheller.warsmash.parsers.fdf.datamodel.fields.Vector4FrameDefinitionField;
|
||||||
|
|
||||||
|
public class GetVector4FieldVisitor implements FrameDefinitionFieldVisitor<Vector4Definition> {
|
||||||
|
public static GetVector4FieldVisitor INSTANCE = new GetVector4FieldVisitor();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Vector4Definition accept(final StringFrameDefinitionField field) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Vector4Definition accept(final StringPairFrameDefinitionField field) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Vector4Definition accept(final FloatFrameDefinitionField field) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Vector4Definition accept(final Vector3FrameDefinitionField field) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Vector4Definition accept(final Vector4FrameDefinitionField field) {
|
||||||
|
return field.getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Vector4Definition accept(final Vector2FrameDefinitionField field) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Vector4Definition accept(final FontFrameDefinitionField field) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Vector4Definition accept(final TextJustifyFrameDefinitionField field) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
169
jassparser/antlr-src/Jass.g4
Normal file
169
jassparser/antlr-src/Jass.g4
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
/**
|
||||||
|
* Define a grammar called Hello
|
||||||
|
*/
|
||||||
|
grammar Jass;
|
||||||
|
|
||||||
|
@header {
|
||||||
|
package com.etheller.interpreter;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
program :
|
||||||
|
newlines
|
||||||
|
|
|
||||||
|
newlines_opt
|
||||||
|
typeDefinitionBlock
|
||||||
|
(block)*
|
||||||
|
(functionBlock)*
|
||||||
|
;
|
||||||
|
|
||||||
|
typeDefinition :
|
||||||
|
TYPE ID EXTENDS ID newlines
|
||||||
|
;
|
||||||
|
|
||||||
|
type :
|
||||||
|
ID # BasicType
|
||||||
|
|
|
||||||
|
ID ARRAY # ArrayType
|
||||||
|
|
|
||||||
|
'nothing' # NothingType
|
||||||
|
;
|
||||||
|
|
||||||
|
global :
|
||||||
|
type ID newlines # BasicGlobal
|
||||||
|
|
|
||||||
|
type ID assignTail newlines # DefinitionGlobal
|
||||||
|
;
|
||||||
|
|
||||||
|
assignTail:
|
||||||
|
EQUALS expression;
|
||||||
|
|
||||||
|
expression:
|
||||||
|
ID # ReferenceExpression
|
||||||
|
|
|
||||||
|
STRING_LITERAL #StringLiteralExpression
|
||||||
|
|
|
||||||
|
INTEGER #IntegerLiteralExpression
|
||||||
|
|
|
||||||
|
FUNCTION ID #FunctionReferenceExpression
|
||||||
|
|
|
||||||
|
NULL # NullExpression
|
||||||
|
|
|
||||||
|
TRUE # TrueExpression
|
||||||
|
|
|
||||||
|
FALSE # FalseExpression
|
||||||
|
|
|
||||||
|
ID '[' expression ']' # ArrayReferenceExpression
|
||||||
|
|
|
||||||
|
functionExpression # FunctionCallExpression
|
||||||
|
|
|
||||||
|
'(' expression ')' # ParentheticalExpression
|
||||||
|
;
|
||||||
|
|
||||||
|
functionExpression:
|
||||||
|
ID '(' argsList ')'
|
||||||
|
;
|
||||||
|
|
||||||
|
argsList:
|
||||||
|
expression # SingleArgument
|
||||||
|
|
|
||||||
|
expression ',' argsList # ListArgument
|
||||||
|
|
|
||||||
|
#EmptyArgument
|
||||||
|
;
|
||||||
|
|
||||||
|
//#booleanExpression:
|
||||||
|
// simpleArithmeticExpression # PassBooleanThroughExpression
|
||||||
|
// |
|
||||||
|
|
||||||
|
statement:
|
||||||
|
CALL functionExpression newlines #CallStatement
|
||||||
|
|
|
||||||
|
SET ID EQUALS expression newlines #SetStatement
|
||||||
|
|
|
||||||
|
SET ID '[' expression ']' EQUALS expression newlines # ArrayedAssignmentStatement
|
||||||
|
|
|
||||||
|
RETURN expression newlines # ReturnStatement
|
||||||
|
;
|
||||||
|
|
||||||
|
param:
|
||||||
|
type ID;
|
||||||
|
|
||||||
|
paramList:
|
||||||
|
param # SingleParameter
|
||||||
|
|
|
||||||
|
param ',' paramList # ListParameter
|
||||||
|
|
|
||||||
|
'nothing' # NothingParameter
|
||||||
|
;
|
||||||
|
|
||||||
|
globalsBlock :
|
||||||
|
GLOBALS newlines (global)* ENDGLOBALS newlines ;
|
||||||
|
|
||||||
|
typeDefinitionBlock :
|
||||||
|
(typeDefinition)*
|
||||||
|
;
|
||||||
|
|
||||||
|
nativeBlock:
|
||||||
|
NATIVE ID TAKES paramList RETURNS type newlines
|
||||||
|
;
|
||||||
|
|
||||||
|
block:
|
||||||
|
globalsBlock
|
||||||
|
|
|
||||||
|
nativeBlock
|
||||||
|
;
|
||||||
|
|
||||||
|
functionBlock:
|
||||||
|
FUNCTION ID TAKES paramList RETURNS type newlines (statement)* ENDFUNCTION newlines
|
||||||
|
;
|
||||||
|
|
||||||
|
newlines:
|
||||||
|
NEWLINES
|
||||||
|
|
|
||||||
|
EOF;
|
||||||
|
|
||||||
|
newlines_opt:
|
||||||
|
NEWLINES
|
||||||
|
|
|
||||||
|
EOF
|
||||||
|
|
|
||||||
|
;
|
||||||
|
|
||||||
|
EQUALS : '=';
|
||||||
|
|
||||||
|
|
||||||
|
GLOBALS : 'globals' ; // globals
|
||||||
|
ENDGLOBALS : 'endglobals' ; // end globals block
|
||||||
|
|
||||||
|
NATIVE : 'native' ;
|
||||||
|
|
||||||
|
FUNCTION : 'function' ; // function
|
||||||
|
TAKES : 'takes' ; // takes
|
||||||
|
RETURNS : 'returns' ;
|
||||||
|
ENDFUNCTION : 'endfunction' ; // endfunction
|
||||||
|
|
||||||
|
CALL : 'call' ;
|
||||||
|
SET : 'set' ;
|
||||||
|
RETURN : 'return' ;
|
||||||
|
|
||||||
|
ARRAY : 'array' ;
|
||||||
|
|
||||||
|
TYPE : 'type';
|
||||||
|
|
||||||
|
EXTENDS : 'extends';
|
||||||
|
|
||||||
|
STRING_LITERAL : ('"'.*?'"');
|
||||||
|
|
||||||
|
INTEGER : [0]|([1-9][0-9]*) ;
|
||||||
|
|
||||||
|
NULL : 'null' ;
|
||||||
|
TRUE : 'true' ;
|
||||||
|
FALSE : 'false' ;
|
||||||
|
|
||||||
|
ID : ([a-zA-Z_][a-zA-Z_0-9]*) ; // match identifiers
|
||||||
|
|
||||||
|
WS : [ \t]+ -> skip ; // skip spaces, tabs
|
||||||
|
|
||||||
|
NEWLINES : NEWLINE+;
|
||||||
|
fragment NEWLINE : '\r' '\n' | '\n' | '\r' | ('//'.*?'\n');
|
49
jassparser/build.gradle
Normal file
49
jassparser/build.gradle
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
apply plugin: "antlr"
|
||||||
|
|
||||||
|
sourceCompatibility = 1.8
|
||||||
|
[compileJava, compileTestJava]*.options*.encoding = 'UTF-8'
|
||||||
|
|
||||||
|
sourceSets.main.java.srcDirs = [ "src/", "build/generated-src" ]
|
||||||
|
sourceSets.main.antlr.srcDirs = [ "antlr-src/" ]
|
||||||
|
|
||||||
|
project.ext.mainClassName = "com.etheller.warsmash.jassparser.Main"
|
||||||
|
|
||||||
|
task run(dependsOn: classes, type: JavaExec) {
|
||||||
|
main = project.mainClassName
|
||||||
|
classpath = sourceSets.main.runtimeClasspath
|
||||||
|
standardInput = System.in
|
||||||
|
ignoreExitValue = true
|
||||||
|
}
|
||||||
|
|
||||||
|
task dist(type: Jar) {
|
||||||
|
from files(sourceSets.main.output.classesDir)
|
||||||
|
from files(sourceSets.main.output.resourcesDir)
|
||||||
|
from {configurations.compile.collect {zipTree(it)}}
|
||||||
|
|
||||||
|
manifest {
|
||||||
|
attributes 'Main-Class': project.mainClassName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dist.dependsOn classes
|
||||||
|
|
||||||
|
eclipse.project {
|
||||||
|
name = appName + "-jassparser"
|
||||||
|
}
|
||||||
|
|
||||||
|
task afterEclipseImport(description: "Post processing after project generation", group: "IDE") {
|
||||||
|
doLast {
|
||||||
|
def classpath = new XmlParser().parse(file(".classpath"))
|
||||||
|
def writer = new FileWriter(file(".classpath"))
|
||||||
|
def printer = new XmlNodePrinter(new PrintWriter(writer))
|
||||||
|
printer.setPreserveWhitespace(true)
|
||||||
|
printer.print(classpath)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
generateGrammarSource {
|
||||||
|
maxHeapSize = "64m"
|
||||||
|
arguments += ["-visitor", "-no-listener"]
|
||||||
|
outputDirectory = file("build/generated-src/com/etheller/warsmash/jassparser")
|
||||||
|
}
|
29
jassparser/src/com/etheller/interpreter/ast/Assignable.java
Normal file
29
jassparser/src/com/etheller/interpreter/ast/Assignable.java
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
package com.etheller.interpreter.ast;
|
||||||
|
|
||||||
|
import com.etheller.interpreter.ast.value.JassType;
|
||||||
|
import com.etheller.interpreter.ast.value.JassValue;
|
||||||
|
import com.etheller.interpreter.ast.value.visitor.JassTypeGettingValueVisitor;
|
||||||
|
|
||||||
|
public class Assignable {
|
||||||
|
private JassValue value;
|
||||||
|
private final JassType type;
|
||||||
|
|
||||||
|
public Assignable(final JassType type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValue(final JassValue value) {
|
||||||
|
if (value.visit(JassTypeGettingValueVisitor.getInstance()) != type) {
|
||||||
|
throw new RuntimeException("Incompatible types");
|
||||||
|
}
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public JassValue getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public JassType getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
}
|
50
jassparser/src/com/etheller/interpreter/ast/JassRunner.java
Normal file
50
jassparser/src/com/etheller/interpreter/ast/JassRunner.java
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
package com.etheller.interpreter.ast;
|
||||||
|
|
||||||
|
import org.antlr.v4.runtime.BaseErrorListener;
|
||||||
|
import org.antlr.v4.runtime.CharStreams;
|
||||||
|
import org.antlr.v4.runtime.CommonTokenStream;
|
||||||
|
import org.antlr.v4.runtime.RecognitionException;
|
||||||
|
import org.antlr.v4.runtime.Recognizer;
|
||||||
|
|
||||||
|
import com.etheller.interpreter.JassLexer;
|
||||||
|
import com.etheller.interpreter.JassParser;
|
||||||
|
import com.etheller.interpreter.ast.visitors.JassProgramVisitor;
|
||||||
|
|
||||||
|
public class JassRunner {
|
||||||
|
public static final boolean REPORT_SYNTAX_ERRORS = true;
|
||||||
|
|
||||||
|
public static void main(final String[] args) {
|
||||||
|
if (args.length < 1) {
|
||||||
|
System.err.println("Usage: <JassFiles> [<AdditionaFile>...]");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final JassProgramVisitor jassProgramVisitor = new JassProgramVisitor();
|
||||||
|
for (final String arg : args) {
|
||||||
|
try {
|
||||||
|
final JassLexer lexer = new JassLexer(CharStreams.fromFileName(arg));
|
||||||
|
final JassParser parser = new JassParser(new CommonTokenStream(lexer));
|
||||||
|
parser.addErrorListener(new BaseErrorListener() {
|
||||||
|
@Override
|
||||||
|
public void syntaxError(final Recognizer<?, ?> recognizer, final Object offendingSymbol,
|
||||||
|
final int line, final int charPositionInLine, final String msg,
|
||||||
|
final RecognitionException e) {
|
||||||
|
if (!REPORT_SYNTAX_ERRORS) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String sourceName = recognizer.getInputStream().getSourceName();
|
||||||
|
if (!sourceName.isEmpty()) {
|
||||||
|
sourceName = String.format("%s:%d:%d: ", sourceName, line, charPositionInLine);
|
||||||
|
}
|
||||||
|
|
||||||
|
System.err.println(sourceName + "line " + line + ":" + charPositionInLine + " " + msg);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
jassProgramVisitor.visit(parser.program());
|
||||||
|
} catch (final Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,38 @@
|
|||||||
|
package com.etheller.interpreter.ast.expression;
|
||||||
|
|
||||||
|
import com.etheller.interpreter.ast.Assignable;
|
||||||
|
import com.etheller.interpreter.ast.scope.GlobalScope;
|
||||||
|
import com.etheller.interpreter.ast.scope.LocalScope;
|
||||||
|
import com.etheller.interpreter.ast.value.ArrayJassValue;
|
||||||
|
import com.etheller.interpreter.ast.value.JassValue;
|
||||||
|
import com.etheller.interpreter.ast.value.visitor.ArrayJassValueVisitor;
|
||||||
|
import com.etheller.interpreter.ast.value.visitor.IntegerJassValueVisitor;
|
||||||
|
|
||||||
|
public class ArrayRefJassExpression implements JassExpression {
|
||||||
|
private final String identifier;
|
||||||
|
private final JassExpression indexExpression;
|
||||||
|
|
||||||
|
public ArrayRefJassExpression(final String identifier, final JassExpression indexExpression) {
|
||||||
|
this.identifier = identifier;
|
||||||
|
this.indexExpression = indexExpression;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue evaluate(final GlobalScope globalScope, final LocalScope localScope) {
|
||||||
|
Assignable variable = localScope.getAssignableLocal(identifier);
|
||||||
|
final JassValue index = indexExpression.evaluate(globalScope, localScope);
|
||||||
|
if (variable == null) {
|
||||||
|
variable = globalScope.getAssignableGlobal(identifier);
|
||||||
|
}
|
||||||
|
if (variable.getValue() == null) {
|
||||||
|
throw new RuntimeException("Unable to use subscript on uninitialized variable");
|
||||||
|
}
|
||||||
|
final ArrayJassValue arrayValue = variable.getValue().visit(ArrayJassValueVisitor.getInstance());
|
||||||
|
if (arrayValue != null) {
|
||||||
|
return arrayValue.get(index.visit(IntegerJassValueVisitor.getInstance()));
|
||||||
|
} else {
|
||||||
|
throw new RuntimeException("Not an array");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
package com.etheller.interpreter.ast.expression;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.etheller.interpreter.ast.function.JassFunction;
|
||||||
|
import com.etheller.interpreter.ast.scope.GlobalScope;
|
||||||
|
import com.etheller.interpreter.ast.scope.LocalScope;
|
||||||
|
import com.etheller.interpreter.ast.value.JassValue;
|
||||||
|
|
||||||
|
public class FunctionCallJassExpression implements JassExpression {
|
||||||
|
private final String functionName;
|
||||||
|
private final List<JassExpression> arguments;
|
||||||
|
|
||||||
|
public FunctionCallJassExpression(final String functionName, final List<JassExpression> arguments) {
|
||||||
|
this.functionName = functionName;
|
||||||
|
this.arguments = arguments;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue evaluate(final GlobalScope globalScope, final LocalScope localScope) {
|
||||||
|
final JassFunction functionByName = globalScope.getFunctionByName(functionName);
|
||||||
|
if (functionByName == null) {
|
||||||
|
throw new RuntimeException("Undefined function: " + functionName);
|
||||||
|
}
|
||||||
|
final List<JassValue> evaluatedExpressions = new ArrayList<>();
|
||||||
|
for (final JassExpression expr : arguments) {
|
||||||
|
final JassValue evaluatedExpression = expr.evaluate(globalScope, localScope);
|
||||||
|
evaluatedExpressions.add(evaluatedExpression);
|
||||||
|
}
|
||||||
|
return functionByName.call(evaluatedExpressions, globalScope);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
package com.etheller.interpreter.ast.expression;
|
||||||
|
|
||||||
|
import com.etheller.interpreter.ast.function.JassFunction;
|
||||||
|
import com.etheller.interpreter.ast.scope.GlobalScope;
|
||||||
|
import com.etheller.interpreter.ast.scope.LocalScope;
|
||||||
|
import com.etheller.interpreter.ast.value.CodeJassValue;
|
||||||
|
import com.etheller.interpreter.ast.value.JassValue;
|
||||||
|
|
||||||
|
public class FunctionReferenceJassExpression implements JassExpression {
|
||||||
|
private final String identifier;
|
||||||
|
|
||||||
|
public FunctionReferenceJassExpression(final String identifier) {
|
||||||
|
this.identifier = identifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue evaluate(final GlobalScope globalScope, final LocalScope localScope) {
|
||||||
|
final JassFunction functionByName = globalScope.getFunctionByName(identifier);
|
||||||
|
if (functionByName == null) {
|
||||||
|
throw new RuntimeException("Unable to find function: " + identifier);
|
||||||
|
}
|
||||||
|
return new CodeJassValue(functionByName);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
package com.etheller.interpreter.ast.expression;
|
||||||
|
|
||||||
|
import com.etheller.interpreter.ast.scope.GlobalScope;
|
||||||
|
import com.etheller.interpreter.ast.scope.LocalScope;
|
||||||
|
import com.etheller.interpreter.ast.value.JassValue;
|
||||||
|
|
||||||
|
public interface JassExpression {
|
||||||
|
JassValue evaluate(GlobalScope globalScope, LocalScope localScope);
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
package com.etheller.interpreter.ast.expression;
|
||||||
|
|
||||||
|
import com.etheller.interpreter.ast.scope.GlobalScope;
|
||||||
|
import com.etheller.interpreter.ast.scope.LocalScope;
|
||||||
|
import com.etheller.interpreter.ast.value.JassValue;
|
||||||
|
|
||||||
|
public class LiteralJassExpression implements JassExpression {
|
||||||
|
private final JassValue value;
|
||||||
|
|
||||||
|
public LiteralJassExpression(final JassValue value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue evaluate(final GlobalScope globalScope, final LocalScope localScope) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
package com.etheller.interpreter.ast.expression;
|
||||||
|
|
||||||
|
import com.etheller.interpreter.ast.Assignable;
|
||||||
|
import com.etheller.interpreter.ast.scope.GlobalScope;
|
||||||
|
import com.etheller.interpreter.ast.scope.LocalScope;
|
||||||
|
import com.etheller.interpreter.ast.value.JassValue;
|
||||||
|
|
||||||
|
public class ReferenceJassExpression implements JassExpression {
|
||||||
|
private final String identifier;
|
||||||
|
|
||||||
|
public ReferenceJassExpression(final String identifier) {
|
||||||
|
this.identifier = identifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue evaluate(final GlobalScope globalScope, final LocalScope localScope) {
|
||||||
|
final Assignable local = localScope.getAssignableLocal(identifier);
|
||||||
|
if (local == null) {
|
||||||
|
return globalScope.getGlobal(identifier);
|
||||||
|
}
|
||||||
|
return local.getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,44 @@
|
|||||||
|
package com.etheller.interpreter.ast.function;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.etheller.interpreter.ast.scope.GlobalScope;
|
||||||
|
import com.etheller.interpreter.ast.scope.LocalScope;
|
||||||
|
import com.etheller.interpreter.ast.value.JassType;
|
||||||
|
import com.etheller.interpreter.ast.value.JassValue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Not a native
|
||||||
|
*
|
||||||
|
* @author Eric
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public abstract class AbstractJassFunction implements JassFunction {
|
||||||
|
protected final List<JassParameter> parameters;
|
||||||
|
protected final JassType returnType;
|
||||||
|
|
||||||
|
public AbstractJassFunction(final List<JassParameter> parameters, final JassType returnType) {
|
||||||
|
this.parameters = parameters;
|
||||||
|
this.returnType = returnType;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final JassValue call(final List<JassValue> arguments, final GlobalScope globalScope) {
|
||||||
|
if (arguments.size() != parameters.size()) {
|
||||||
|
throw new RuntimeException("Invalid number of arguments passed to function");
|
||||||
|
}
|
||||||
|
final LocalScope localScope = new LocalScope();
|
||||||
|
for (int i = 0; i < parameters.size(); i++) {
|
||||||
|
final JassParameter parameter = parameters.get(i);
|
||||||
|
final JassValue argument = arguments.get(i);
|
||||||
|
if (!parameter.matchesType(argument)) {
|
||||||
|
throw new RuntimeException("Invalid type for specified argument");
|
||||||
|
}
|
||||||
|
localScope.createLocal(parameter.getIdentifier(), parameter.getType(), argument);
|
||||||
|
}
|
||||||
|
return innerCall(arguments, globalScope, localScope);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract JassValue innerCall(final List<JassValue> arguments, final GlobalScope globalScope,
|
||||||
|
final LocalScope localScope);
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
package com.etheller.interpreter.ast.function;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.etheller.interpreter.ast.scope.GlobalScope;
|
||||||
|
import com.etheller.interpreter.ast.value.JassValue;
|
||||||
|
|
||||||
|
public interface JassFunction {
|
||||||
|
JassValue call(List<JassValue> arguments, GlobalScope globalScope);
|
||||||
|
}
|
@ -0,0 +1,33 @@
|
|||||||
|
package com.etheller.interpreter.ast.function;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import com.etheller.interpreter.ast.scope.GlobalScope;
|
||||||
|
import com.etheller.interpreter.ast.value.JassType;
|
||||||
|
|
||||||
|
public class JassNativeManager {
|
||||||
|
private final Map<String, JassFunction> nameToNativeCode;
|
||||||
|
private final Set<String> registeredNativeNames = new HashSet<>();
|
||||||
|
|
||||||
|
public JassNativeManager() {
|
||||||
|
this.nameToNativeCode = new HashMap<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void registerNativeCode(final String name, final List<JassParameter> parameters, final JassType returnType,
|
||||||
|
final GlobalScope globals) {
|
||||||
|
if (this.registeredNativeNames.contains(name)) {
|
||||||
|
throw new RuntimeException("Native already registered: " + name);
|
||||||
|
}
|
||||||
|
final JassFunction nativeCode = this.nameToNativeCode.remove(name);
|
||||||
|
globals.defineFunction(name, new NativeJassFunction(parameters, returnType, name, nativeCode));
|
||||||
|
this.registeredNativeNames.add(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void checkUnregisteredNatives() {
|
||||||
|
// TODO maybe do this later
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
package com.etheller.interpreter.ast.function;
|
||||||
|
|
||||||
|
import com.etheller.interpreter.ast.value.JassType;
|
||||||
|
import com.etheller.interpreter.ast.value.JassValue;
|
||||||
|
import com.etheller.interpreter.ast.value.visitor.JassTypeGettingValueVisitor;
|
||||||
|
|
||||||
|
public class JassParameter {
|
||||||
|
private final JassType type;
|
||||||
|
private final String identifier;
|
||||||
|
|
||||||
|
public JassParameter(final JassType type, final String identifier) {
|
||||||
|
this.type = type;
|
||||||
|
this.identifier = identifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getIdentifier() {
|
||||||
|
return identifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
public JassType getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean matchesType(final JassValue value) {
|
||||||
|
return type == value.visit(JassTypeGettingValueVisitor.getInstance());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
package com.etheller.interpreter.ast.function;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.etheller.interpreter.ast.scope.GlobalScope;
|
||||||
|
import com.etheller.interpreter.ast.scope.LocalScope;
|
||||||
|
import com.etheller.interpreter.ast.value.JassType;
|
||||||
|
import com.etheller.interpreter.ast.value.JassValue;
|
||||||
|
|
||||||
|
public class NativeJassFunction extends AbstractJassFunction {
|
||||||
|
private final String name;
|
||||||
|
private final JassFunction implementation;
|
||||||
|
|
||||||
|
public NativeJassFunction(final List<JassParameter> parameters, final JassType returnType, final String name,
|
||||||
|
final JassFunction impl) {
|
||||||
|
super(parameters, returnType);
|
||||||
|
this.name = name;
|
||||||
|
implementation = impl;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected JassValue innerCall(final List<JassValue> arguments, final GlobalScope globalScope,
|
||||||
|
final LocalScope localScope) {
|
||||||
|
return implementation.call(arguments, globalScope);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,44 @@
|
|||||||
|
package com.etheller.interpreter.ast.function;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.etheller.interpreter.ast.scope.GlobalScope;
|
||||||
|
import com.etheller.interpreter.ast.scope.LocalScope;
|
||||||
|
import com.etheller.interpreter.ast.statement.JassStatement;
|
||||||
|
import com.etheller.interpreter.ast.value.JassType;
|
||||||
|
import com.etheller.interpreter.ast.value.JassValue;
|
||||||
|
import com.etheller.interpreter.ast.value.visitor.JassTypeGettingValueVisitor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Not a native
|
||||||
|
*
|
||||||
|
* @author Eric
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public final class UserJassFunction extends AbstractJassFunction {
|
||||||
|
private final List<JassStatement> statements;
|
||||||
|
|
||||||
|
public UserJassFunction(final List<JassStatement> statements, final List<JassParameter> parameters,
|
||||||
|
final JassType returnType) {
|
||||||
|
super(parameters, returnType);
|
||||||
|
this.statements = statements;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue innerCall(final List<JassValue> arguments, final GlobalScope globalScope,
|
||||||
|
final LocalScope localScope) {
|
||||||
|
for (final JassStatement statement : statements) {
|
||||||
|
final JassValue returnValue = statement.execute(globalScope, localScope);
|
||||||
|
if (returnValue != null) {
|
||||||
|
if (returnValue.visit(JassTypeGettingValueVisitor.getInstance()) != returnType) {
|
||||||
|
throw new RuntimeException("Invalid return type");
|
||||||
|
}
|
||||||
|
return returnValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (JassType.NOTHING != returnType) {
|
||||||
|
throw new RuntimeException("Invalid return type");
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,94 @@
|
|||||||
|
package com.etheller.interpreter.ast.scope;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import com.etheller.interpreter.ast.Assignable;
|
||||||
|
import com.etheller.interpreter.ast.function.JassFunction;
|
||||||
|
import com.etheller.interpreter.ast.value.ArrayJassType;
|
||||||
|
import com.etheller.interpreter.ast.value.ArrayJassValue;
|
||||||
|
import com.etheller.interpreter.ast.value.JassType;
|
||||||
|
import com.etheller.interpreter.ast.value.JassValue;
|
||||||
|
import com.etheller.interpreter.ast.value.PrimitiveJassType;
|
||||||
|
import com.etheller.interpreter.ast.value.visitor.ArrayPrimitiveTypeVisitor;
|
||||||
|
|
||||||
|
public final class GlobalScope {
|
||||||
|
private final Map<String, Assignable> globals = new HashMap<>();
|
||||||
|
private final Map<String, JassFunction> functions = new HashMap<>();
|
||||||
|
private final Map<String, JassType> types = new HashMap<>();
|
||||||
|
|
||||||
|
public void createGlobalArray(final String name, final JassType type) {
|
||||||
|
final Assignable assignable = new Assignable(type);
|
||||||
|
assignable.setValue(new ArrayJassValue((ArrayJassType) type)); // TODO less bad code
|
||||||
|
globals.put(name, assignable);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void createGlobal(final String name, final JassType type) {
|
||||||
|
globals.put(name, new Assignable(type));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void createGlobal(final String name, final JassType type, final JassValue value) {
|
||||||
|
final Assignable assignable = new Assignable(type);
|
||||||
|
assignable.setValue(value);
|
||||||
|
globals.put(name, assignable);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setGlobal(final String name, final JassValue value) {
|
||||||
|
final Assignable assignable = globals.get(name);
|
||||||
|
if (assignable == null) {
|
||||||
|
throw new RuntimeException("Undefined global: " + name);
|
||||||
|
}
|
||||||
|
if (assignable.getType().visit(ArrayPrimitiveTypeVisitor.getInstance()) != null) {
|
||||||
|
throw new RuntimeException("Unable to assign array variable: " + name);
|
||||||
|
}
|
||||||
|
assignable.setValue(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public JassValue getGlobal(final String name) {
|
||||||
|
final Assignable global = globals.get(name);
|
||||||
|
if (global == null) {
|
||||||
|
throw new RuntimeException("Undefined global: " + name);
|
||||||
|
}
|
||||||
|
return global.getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Assignable getAssignableGlobal(final String name) {
|
||||||
|
return globals.get(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void defineFunction(final String name, final JassFunction function) {
|
||||||
|
functions.put(name, function);
|
||||||
|
}
|
||||||
|
|
||||||
|
public JassFunction getFunctionByName(final String name) {
|
||||||
|
return functions.get(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public PrimitiveJassType parseType(final String text) {
|
||||||
|
if (text.equals("string")) {
|
||||||
|
return JassType.STRING;
|
||||||
|
} else if (text.equals("integer")) {
|
||||||
|
return JassType.INTEGER;
|
||||||
|
} else if (text.equals("boolean")) {
|
||||||
|
return JassType.BOOLEAN;
|
||||||
|
} else if (text.equals("real")) {
|
||||||
|
return JassType.REAL;
|
||||||
|
} else if (text.equals("code")) {
|
||||||
|
return JassType.CODE;
|
||||||
|
} else if (text.equals("nothing")) {
|
||||||
|
return JassType.NOTHING;
|
||||||
|
} else {
|
||||||
|
throw new RuntimeException("Unknown type: " + text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public JassType parseArrayType(final String primitiveTypeName) {
|
||||||
|
final String arrayTypeName = primitiveTypeName + " array";
|
||||||
|
JassType arrayType = types.get(arrayTypeName);
|
||||||
|
if (arrayType == null) {
|
||||||
|
arrayType = new ArrayJassType(parseType(primitiveTypeName));
|
||||||
|
types.put(arrayTypeName, arrayType);
|
||||||
|
}
|
||||||
|
return arrayType;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,42 @@
|
|||||||
|
package com.etheller.interpreter.ast.scope;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import com.etheller.interpreter.ast.Assignable;
|
||||||
|
import com.etheller.interpreter.ast.value.JassType;
|
||||||
|
import com.etheller.interpreter.ast.value.JassValue;
|
||||||
|
|
||||||
|
public final class LocalScope {
|
||||||
|
private final Map<String, Assignable> locals = new HashMap<>();
|
||||||
|
|
||||||
|
public void createLocal(final String name, final JassType type) {
|
||||||
|
locals.put(name, new Assignable(type));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void createLocal(final String name, final JassType type, final JassValue value) {
|
||||||
|
final Assignable assignable = new Assignable(type);
|
||||||
|
assignable.setValue(value);
|
||||||
|
locals.put(name, assignable);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLocal(final String name, final JassValue value) {
|
||||||
|
final Assignable assignable = locals.get(name);
|
||||||
|
if (assignable == null) {
|
||||||
|
throw new RuntimeException("Undefined local variable: " + name);
|
||||||
|
}
|
||||||
|
assignable.setValue(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public JassValue getLocal(final String name) {
|
||||||
|
final Assignable local = locals.get(name);
|
||||||
|
if (local == null) {
|
||||||
|
throw new RuntimeException("Undefined local variable: " + name);
|
||||||
|
}
|
||||||
|
return local.getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Assignable getAssignableLocal(final String name) {
|
||||||
|
return locals.get(name);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
package com.etheller.interpreter.ast.scope;
|
||||||
|
|
||||||
|
public class TypeDefinition {
|
||||||
|
private final String name;
|
||||||
|
private final String supertype;
|
||||||
|
|
||||||
|
public TypeDefinition(final String name, final String supertype) {
|
||||||
|
this.name = name;
|
||||||
|
this.supertype = supertype;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,44 @@
|
|||||||
|
package com.etheller.interpreter.ast.statement;
|
||||||
|
|
||||||
|
import com.etheller.interpreter.ast.Assignable;
|
||||||
|
import com.etheller.interpreter.ast.expression.JassExpression;
|
||||||
|
import com.etheller.interpreter.ast.scope.GlobalScope;
|
||||||
|
import com.etheller.interpreter.ast.scope.LocalScope;
|
||||||
|
import com.etheller.interpreter.ast.value.ArrayJassValue;
|
||||||
|
import com.etheller.interpreter.ast.value.JassValue;
|
||||||
|
import com.etheller.interpreter.ast.value.visitor.ArrayJassValueVisitor;
|
||||||
|
import com.etheller.interpreter.ast.value.visitor.IntegerJassValueVisitor;
|
||||||
|
|
||||||
|
public class JassArrayedAssignmentStatement implements JassStatement {
|
||||||
|
private final String identifier;
|
||||||
|
private final JassExpression indexExpression;
|
||||||
|
private final JassExpression expression;
|
||||||
|
|
||||||
|
public JassArrayedAssignmentStatement(final String identifier, final JassExpression indexExpression,
|
||||||
|
final JassExpression expression) {
|
||||||
|
this.identifier = identifier;
|
||||||
|
this.indexExpression = indexExpression;
|
||||||
|
this.expression = expression;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue execute(final GlobalScope globalScope, final LocalScope localScope) {
|
||||||
|
Assignable variable = localScope.getAssignableLocal(identifier);
|
||||||
|
final JassValue index = indexExpression.evaluate(globalScope, localScope);
|
||||||
|
if (variable == null) {
|
||||||
|
variable = globalScope.getAssignableGlobal(identifier);
|
||||||
|
}
|
||||||
|
if (variable.getValue() == null) {
|
||||||
|
throw new RuntimeException("Unable to assign uninitialized array");
|
||||||
|
}
|
||||||
|
final ArrayJassValue arrayValue = variable.getValue().visit(ArrayJassValueVisitor.getInstance());
|
||||||
|
if (arrayValue != null) {
|
||||||
|
arrayValue.set(index.visit(IntegerJassValueVisitor.getInstance()),
|
||||||
|
expression.evaluate(globalScope, localScope));
|
||||||
|
} else {
|
||||||
|
throw new RuntimeException("Not an array");
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,37 @@
|
|||||||
|
package com.etheller.interpreter.ast.statement;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.etheller.interpreter.ast.expression.JassExpression;
|
||||||
|
import com.etheller.interpreter.ast.function.JassFunction;
|
||||||
|
import com.etheller.interpreter.ast.scope.GlobalScope;
|
||||||
|
import com.etheller.interpreter.ast.scope.LocalScope;
|
||||||
|
import com.etheller.interpreter.ast.value.JassValue;
|
||||||
|
|
||||||
|
public class JassCallStatement implements JassStatement {
|
||||||
|
private final String functionName;
|
||||||
|
private final List<JassExpression> arguments;
|
||||||
|
|
||||||
|
public JassCallStatement(final String functionName, final List<JassExpression> arguments) {
|
||||||
|
this.functionName = functionName;
|
||||||
|
this.arguments = arguments;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue execute(final GlobalScope globalScope, final LocalScope localScope) {
|
||||||
|
final JassFunction functionByName = globalScope.getFunctionByName(functionName);
|
||||||
|
if (functionByName == null) {
|
||||||
|
throw new RuntimeException("Undefined function: " + functionName);
|
||||||
|
}
|
||||||
|
final List<JassValue> evaluatedExpressions = new ArrayList<>();
|
||||||
|
for (final JassExpression expr : arguments) {
|
||||||
|
final JassValue evaluatedExpression = expr.evaluate(globalScope, localScope);
|
||||||
|
evaluatedExpressions.add(evaluatedExpression);
|
||||||
|
}
|
||||||
|
functionByName.call(evaluatedExpressions, globalScope);
|
||||||
|
// throw away return value
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
package com.etheller.interpreter.ast.statement;
|
||||||
|
|
||||||
|
import com.etheller.interpreter.ast.expression.JassExpression;
|
||||||
|
import com.etheller.interpreter.ast.scope.GlobalScope;
|
||||||
|
import com.etheller.interpreter.ast.scope.LocalScope;
|
||||||
|
import com.etheller.interpreter.ast.value.JassValue;
|
||||||
|
|
||||||
|
public class JassReturnStatement implements JassStatement {
|
||||||
|
private final JassExpression expression;
|
||||||
|
|
||||||
|
public JassReturnStatement(final JassExpression expression) {
|
||||||
|
this.expression = expression;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue execute(final GlobalScope globalScope, final LocalScope localScope) {
|
||||||
|
return expression.evaluate(globalScope, localScope);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,29 @@
|
|||||||
|
package com.etheller.interpreter.ast.statement;
|
||||||
|
|
||||||
|
import com.etheller.interpreter.ast.Assignable;
|
||||||
|
import com.etheller.interpreter.ast.expression.JassExpression;
|
||||||
|
import com.etheller.interpreter.ast.scope.GlobalScope;
|
||||||
|
import com.etheller.interpreter.ast.scope.LocalScope;
|
||||||
|
import com.etheller.interpreter.ast.value.JassValue;
|
||||||
|
|
||||||
|
public class JassSetStatement implements JassStatement {
|
||||||
|
private final String identifier;
|
||||||
|
private final JassExpression expression;
|
||||||
|
|
||||||
|
public JassSetStatement(final String identifier, final JassExpression expression) {
|
||||||
|
this.identifier = identifier;
|
||||||
|
this.expression = expression;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassValue execute(final GlobalScope globalScope, final LocalScope localScope) {
|
||||||
|
final Assignable local = localScope.getAssignableLocal(identifier);
|
||||||
|
if (local != null) {
|
||||||
|
local.setValue(expression.evaluate(globalScope, localScope));
|
||||||
|
} else {
|
||||||
|
globalScope.setGlobal(identifier, expression.evaluate(globalScope, localScope));
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,11 @@
|
|||||||
|
package com.etheller.interpreter.ast.statement;
|
||||||
|
|
||||||
|
import com.etheller.interpreter.ast.scope.GlobalScope;
|
||||||
|
import com.etheller.interpreter.ast.scope.LocalScope;
|
||||||
|
import com.etheller.interpreter.ast.value.JassValue;
|
||||||
|
|
||||||
|
public interface JassStatement {
|
||||||
|
// When a value is returned, this indicates a RETURN statement,
|
||||||
|
// and will end outer execution
|
||||||
|
JassValue execute(GlobalScope globalScope, LocalScope localScope);
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
package com.etheller.interpreter.ast.value;
|
||||||
|
|
||||||
|
public class ArrayJassType implements JassType {
|
||||||
|
private final PrimitiveJassType primitiveType;
|
||||||
|
|
||||||
|
public ArrayJassType(final PrimitiveJassType primitiveType) {
|
||||||
|
this.primitiveType = primitiveType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PrimitiveJassType getPrimitiveType() {
|
||||||
|
return primitiveType;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <TYPE> TYPE visit(final JassTypeVisitor<TYPE> visitor) {
|
||||||
|
return visitor.accept(this);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
package com.etheller.interpreter.ast.value;
|
||||||
|
|
||||||
|
import com.etheller.interpreter.ast.value.visitor.JassTypeGettingValueVisitor;
|
||||||
|
|
||||||
|
public class ArrayJassValue implements JassValue {
|
||||||
|
private final JassValue[] data = new JassValue[8192]; // that's the array size in JASS
|
||||||
|
private final ArrayJassType type;
|
||||||
|
|
||||||
|
public ArrayJassValue(final ArrayJassType type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <TYPE> TYPE visit(final JassValueVisitor<TYPE> visitor) {
|
||||||
|
return visitor.accept(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void set(final int index, final JassValue value) {
|
||||||
|
if (value.visit(JassTypeGettingValueVisitor.getInstance()) != type.getPrimitiveType()) {
|
||||||
|
throw new IllegalStateException(
|
||||||
|
"Illegal type for assignment to " + type.getPrimitiveType().getName() + " array");
|
||||||
|
}
|
||||||
|
data[index] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public JassValue get(final int index) {
|
||||||
|
return data[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArrayJassType getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
package com.etheller.interpreter.ast.value;
|
||||||
|
|
||||||
|
public class BooleanJassValue implements JassValue {
|
||||||
|
private final boolean value;
|
||||||
|
|
||||||
|
public BooleanJassValue(final boolean value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <TYPE> TYPE visit(final JassValueVisitor<TYPE> visitor) {
|
||||||
|
return visitor.accept(this);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
package com.etheller.interpreter.ast.value;
|
||||||
|
|
||||||
|
import com.etheller.interpreter.ast.function.JassFunction;
|
||||||
|
|
||||||
|
public class CodeJassValue implements JassValue {
|
||||||
|
private final JassFunction value;
|
||||||
|
|
||||||
|
public CodeJassValue(final JassFunction value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public JassFunction getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <TYPE> TYPE visit(final JassValueVisitor<TYPE> visitor) {
|
||||||
|
return visitor.accept(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
package com.etheller.interpreter.ast.value;
|
||||||
|
|
||||||
|
public class IntegerJassValue implements JassValue {
|
||||||
|
private final int value;
|
||||||
|
|
||||||
|
public IntegerJassValue(final int value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <TYPE> TYPE visit(final JassValueVisitor<TYPE> visitor) {
|
||||||
|
return visitor.accept(this);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,12 @@
|
|||||||
|
package com.etheller.interpreter.ast.value;
|
||||||
|
|
||||||
|
public interface JassType {
|
||||||
|
<TYPE> TYPE visit(JassTypeVisitor<TYPE> visitor);
|
||||||
|
|
||||||
|
public static final PrimitiveJassType INTEGER = new PrimitiveJassType("integer");
|
||||||
|
public static final PrimitiveJassType STRING = new PrimitiveJassType("string");
|
||||||
|
public static final PrimitiveJassType CODE = new PrimitiveJassType("code");
|
||||||
|
public static final PrimitiveJassType REAL = new PrimitiveJassType("real");
|
||||||
|
public static final PrimitiveJassType BOOLEAN = new PrimitiveJassType("boolean");
|
||||||
|
public static final PrimitiveJassType NOTHING = new PrimitiveJassType("nothing");
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
package com.etheller.interpreter.ast.value;
|
||||||
|
|
||||||
|
public interface JassTypeVisitor<TYPE> {
|
||||||
|
TYPE accept(PrimitiveJassType primitiveType);
|
||||||
|
|
||||||
|
TYPE accept(ArrayJassType arrayType);
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
package com.etheller.interpreter.ast.value;
|
||||||
|
|
||||||
|
public interface JassValue {
|
||||||
|
<TYPE> TYPE visit(JassValueVisitor<TYPE> visitor);
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
package com.etheller.interpreter.ast.value;
|
||||||
|
|
||||||
|
public interface JassValueVisitor<TYPE> {
|
||||||
|
TYPE accept(IntegerJassValue value);
|
||||||
|
|
||||||
|
TYPE accept(RealJassValue value);
|
||||||
|
|
||||||
|
TYPE accept(BooleanJassValue value);
|
||||||
|
|
||||||
|
TYPE accept(StringJassValue value);
|
||||||
|
|
||||||
|
TYPE accept(CodeJassValue value);
|
||||||
|
|
||||||
|
TYPE accept(ArrayJassValue value);
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
package com.etheller.interpreter.ast.value;
|
||||||
|
|
||||||
|
public class PrimitiveJassType implements JassType {
|
||||||
|
private final String name;
|
||||||
|
|
||||||
|
public PrimitiveJassType(final String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <TYPE> TYPE visit(final JassTypeVisitor<TYPE> visitor) {
|
||||||
|
return visitor.accept(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
package com.etheller.interpreter.ast.value;
|
||||||
|
|
||||||
|
public class RealJassValue implements JassValue {
|
||||||
|
private final double value;
|
||||||
|
|
||||||
|
public RealJassValue(final double value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <TYPE> TYPE visit(final JassValueVisitor<TYPE> visitor) {
|
||||||
|
return visitor.accept(this);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
package com.etheller.interpreter.ast.value;
|
||||||
|
|
||||||
|
public class StringJassValue implements JassValue {
|
||||||
|
private final String value;
|
||||||
|
|
||||||
|
public StringJassValue(final String value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <TYPE> TYPE visit(final JassValueVisitor<TYPE> visitor) {
|
||||||
|
return visitor.accept(this);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,48 @@
|
|||||||
|
package com.etheller.interpreter.ast.value.visitor;
|
||||||
|
|
||||||
|
import com.etheller.interpreter.ast.value.ArrayJassValue;
|
||||||
|
import com.etheller.interpreter.ast.value.BooleanJassValue;
|
||||||
|
import com.etheller.interpreter.ast.value.CodeJassValue;
|
||||||
|
import com.etheller.interpreter.ast.value.IntegerJassValue;
|
||||||
|
import com.etheller.interpreter.ast.value.JassValueVisitor;
|
||||||
|
import com.etheller.interpreter.ast.value.RealJassValue;
|
||||||
|
import com.etheller.interpreter.ast.value.StringJassValue;
|
||||||
|
|
||||||
|
public class ArrayJassValueVisitor implements JassValueVisitor<ArrayJassValue> {
|
||||||
|
private static final ArrayJassValueVisitor INSTANCE = new ArrayJassValueVisitor();
|
||||||
|
|
||||||
|
public static ArrayJassValueVisitor getInstance() {
|
||||||
|
return INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ArrayJassValue accept(final IntegerJassValue value) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ArrayJassValue accept(final RealJassValue value) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ArrayJassValue accept(final BooleanJassValue value) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ArrayJassValue accept(final StringJassValue value) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ArrayJassValue accept(final CodeJassValue value) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ArrayJassValue accept(final ArrayJassValue value) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
package com.etheller.interpreter.ast.value.visitor;
|
||||||
|
|
||||||
|
import com.etheller.interpreter.ast.value.ArrayJassType;
|
||||||
|
import com.etheller.interpreter.ast.value.JassTypeVisitor;
|
||||||
|
import com.etheller.interpreter.ast.value.PrimitiveJassType;
|
||||||
|
|
||||||
|
public class ArrayPrimitiveTypeVisitor implements JassTypeVisitor<PrimitiveJassType> {
|
||||||
|
private static final ArrayPrimitiveTypeVisitor INSTANCE = new ArrayPrimitiveTypeVisitor();
|
||||||
|
|
||||||
|
public static ArrayPrimitiveTypeVisitor getInstance() {
|
||||||
|
return INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PrimitiveJassType accept(final PrimitiveJassType primitiveType) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PrimitiveJassType accept(final ArrayJassType arrayType) {
|
||||||
|
return arrayType.getPrimitiveType();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,48 @@
|
|||||||
|
package com.etheller.interpreter.ast.value.visitor;
|
||||||
|
|
||||||
|
import com.etheller.interpreter.ast.value.ArrayJassValue;
|
||||||
|
import com.etheller.interpreter.ast.value.BooleanJassValue;
|
||||||
|
import com.etheller.interpreter.ast.value.CodeJassValue;
|
||||||
|
import com.etheller.interpreter.ast.value.IntegerJassValue;
|
||||||
|
import com.etheller.interpreter.ast.value.JassValueVisitor;
|
||||||
|
import com.etheller.interpreter.ast.value.RealJassValue;
|
||||||
|
import com.etheller.interpreter.ast.value.StringJassValue;
|
||||||
|
|
||||||
|
public class IntegerJassValueVisitor implements JassValueVisitor<Integer> {
|
||||||
|
private static final IntegerJassValueVisitor INSTANCE = new IntegerJassValueVisitor();
|
||||||
|
|
||||||
|
public static IntegerJassValueVisitor getInstance() {
|
||||||
|
return INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer accept(final IntegerJassValue value) {
|
||||||
|
return value.getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer accept(final RealJassValue value) {
|
||||||
|
return (int) value.getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer accept(final BooleanJassValue value) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer accept(final StringJassValue value) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer accept(final CodeJassValue value) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer accept(final ArrayJassValue value) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,49 @@
|
|||||||
|
package com.etheller.interpreter.ast.value.visitor;
|
||||||
|
|
||||||
|
import com.etheller.interpreter.ast.function.JassFunction;
|
||||||
|
import com.etheller.interpreter.ast.value.ArrayJassValue;
|
||||||
|
import com.etheller.interpreter.ast.value.BooleanJassValue;
|
||||||
|
import com.etheller.interpreter.ast.value.CodeJassValue;
|
||||||
|
import com.etheller.interpreter.ast.value.IntegerJassValue;
|
||||||
|
import com.etheller.interpreter.ast.value.JassValueVisitor;
|
||||||
|
import com.etheller.interpreter.ast.value.RealJassValue;
|
||||||
|
import com.etheller.interpreter.ast.value.StringJassValue;
|
||||||
|
|
||||||
|
public class JassFunctionJassValueVisitor implements JassValueVisitor<JassFunction> {
|
||||||
|
private static final JassFunctionJassValueVisitor INSTANCE = new JassFunctionJassValueVisitor();
|
||||||
|
|
||||||
|
public static JassFunctionJassValueVisitor getInstance() {
|
||||||
|
return INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassFunction accept(final IntegerJassValue value) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassFunction accept(final RealJassValue value) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassFunction accept(final BooleanJassValue value) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassFunction accept(final StringJassValue value) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassFunction accept(final CodeJassValue value) {
|
||||||
|
return value.getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassFunction accept(final ArrayJassValue value) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,49 @@
|
|||||||
|
package com.etheller.interpreter.ast.value.visitor;
|
||||||
|
|
||||||
|
import com.etheller.interpreter.ast.value.ArrayJassValue;
|
||||||
|
import com.etheller.interpreter.ast.value.BooleanJassValue;
|
||||||
|
import com.etheller.interpreter.ast.value.CodeJassValue;
|
||||||
|
import com.etheller.interpreter.ast.value.IntegerJassValue;
|
||||||
|
import com.etheller.interpreter.ast.value.JassType;
|
||||||
|
import com.etheller.interpreter.ast.value.JassValueVisitor;
|
||||||
|
import com.etheller.interpreter.ast.value.RealJassValue;
|
||||||
|
import com.etheller.interpreter.ast.value.StringJassValue;
|
||||||
|
|
||||||
|
public class JassTypeGettingValueVisitor implements JassValueVisitor<JassType> {
|
||||||
|
public static JassTypeGettingValueVisitor INSTANCE = new JassTypeGettingValueVisitor();
|
||||||
|
|
||||||
|
public static JassTypeGettingValueVisitor getInstance() {
|
||||||
|
return INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassType accept(final IntegerJassValue value) {
|
||||||
|
return JassType.INTEGER;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassType accept(final RealJassValue value) {
|
||||||
|
return JassType.REAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassType accept(final BooleanJassValue value) {
|
||||||
|
return JassType.BOOLEAN;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassType accept(final StringJassValue value) {
|
||||||
|
return JassType.STRING;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassType accept(final CodeJassValue value) {
|
||||||
|
return JassType.CODE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassType accept(final ArrayJassValue value) {
|
||||||
|
return value.getType();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,48 @@
|
|||||||
|
package com.etheller.interpreter.ast.value.visitor;
|
||||||
|
|
||||||
|
import com.etheller.interpreter.ast.value.ArrayJassValue;
|
||||||
|
import com.etheller.interpreter.ast.value.BooleanJassValue;
|
||||||
|
import com.etheller.interpreter.ast.value.CodeJassValue;
|
||||||
|
import com.etheller.interpreter.ast.value.IntegerJassValue;
|
||||||
|
import com.etheller.interpreter.ast.value.JassValueVisitor;
|
||||||
|
import com.etheller.interpreter.ast.value.RealJassValue;
|
||||||
|
import com.etheller.interpreter.ast.value.StringJassValue;
|
||||||
|
|
||||||
|
public class StringJassValueVisitor implements JassValueVisitor<String> {
|
||||||
|
private static final StringJassValueVisitor INSTANCE = new StringJassValueVisitor();
|
||||||
|
|
||||||
|
public static StringJassValueVisitor getInstance() {
|
||||||
|
return INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String accept(final IntegerJassValue value) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String accept(final RealJassValue value) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String accept(final BooleanJassValue value) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String accept(final StringJassValue value) {
|
||||||
|
return value.getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String accept(final CodeJassValue value) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String accept(final ArrayJassValue value) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
package com.etheller.interpreter.ast.visitors;
|
||||||
|
|
||||||
|
public class ArgumentExpressionHandler {
|
||||||
|
protected JassArgumentsVisitor argumentsVisitor;
|
||||||
|
protected JassExpressionVisitor expressionVisitor;
|
||||||
|
|
||||||
|
public void setJassArgumentsVisitor(final JassArgumentsVisitor jassArgumentsVisitor) {
|
||||||
|
this.argumentsVisitor = jassArgumentsVisitor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setJassExpressionVisitor(final JassExpressionVisitor jassExpressionVisitor) {
|
||||||
|
this.expressionVisitor = jassExpressionVisitor;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,38 @@
|
|||||||
|
package com.etheller.interpreter.ast.visitors;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.etheller.interpreter.JassBaseVisitor;
|
||||||
|
import com.etheller.interpreter.JassParser.EmptyArgumentContext;
|
||||||
|
import com.etheller.interpreter.JassParser.ListArgumentContext;
|
||||||
|
import com.etheller.interpreter.JassParser.SingleArgumentContext;
|
||||||
|
import com.etheller.interpreter.ast.expression.JassExpression;
|
||||||
|
|
||||||
|
public class JassArgumentsVisitor extends JassBaseVisitor<List<JassExpression>> {
|
||||||
|
private final ArgumentExpressionHandler argumentExpressionHandler;
|
||||||
|
|
||||||
|
public JassArgumentsVisitor(final ArgumentExpressionHandler argumentExpressionHandler) {
|
||||||
|
this.argumentExpressionHandler = argumentExpressionHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<JassExpression> visitSingleArgument(final SingleArgumentContext ctx) {
|
||||||
|
final List<JassExpression> list = new LinkedList<>();
|
||||||
|
list.add(argumentExpressionHandler.expressionVisitor.visit(ctx.expression()));
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<JassExpression> visitListArgument(final ListArgumentContext ctx) {
|
||||||
|
final List<JassExpression> list = visit(ctx.argsList());
|
||||||
|
list.add(0, argumentExpressionHandler.expressionVisitor.visit(ctx.expression()));
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<JassExpression> visitEmptyArgument(final EmptyArgumentContext ctx) {
|
||||||
|
return Collections.EMPTY_LIST;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,77 @@
|
|||||||
|
package com.etheller.interpreter.ast.visitors;
|
||||||
|
|
||||||
|
import com.etheller.interpreter.JassBaseVisitor;
|
||||||
|
import com.etheller.interpreter.JassParser.ArrayReferenceExpressionContext;
|
||||||
|
import com.etheller.interpreter.JassParser.FalseExpressionContext;
|
||||||
|
import com.etheller.interpreter.JassParser.FunctionCallExpressionContext;
|
||||||
|
import com.etheller.interpreter.JassParser.FunctionReferenceExpressionContext;
|
||||||
|
import com.etheller.interpreter.JassParser.IntegerLiteralExpressionContext;
|
||||||
|
import com.etheller.interpreter.JassParser.ParentheticalExpressionContext;
|
||||||
|
import com.etheller.interpreter.JassParser.ReferenceExpressionContext;
|
||||||
|
import com.etheller.interpreter.JassParser.StringLiteralExpressionContext;
|
||||||
|
import com.etheller.interpreter.JassParser.TrueExpressionContext;
|
||||||
|
import com.etheller.interpreter.ast.expression.ArrayRefJassExpression;
|
||||||
|
import com.etheller.interpreter.ast.expression.FunctionCallJassExpression;
|
||||||
|
import com.etheller.interpreter.ast.expression.FunctionReferenceJassExpression;
|
||||||
|
import com.etheller.interpreter.ast.expression.JassExpression;
|
||||||
|
import com.etheller.interpreter.ast.expression.LiteralJassExpression;
|
||||||
|
import com.etheller.interpreter.ast.expression.ReferenceJassExpression;
|
||||||
|
import com.etheller.interpreter.ast.value.BooleanJassValue;
|
||||||
|
import com.etheller.interpreter.ast.value.IntegerJassValue;
|
||||||
|
import com.etheller.interpreter.ast.value.StringJassValue;
|
||||||
|
|
||||||
|
public class JassExpressionVisitor extends JassBaseVisitor<JassExpression> {
|
||||||
|
private final ArgumentExpressionHandler argumentExpressionHandler;
|
||||||
|
|
||||||
|
public JassExpressionVisitor(final ArgumentExpressionHandler argumentExpressionHandler) {
|
||||||
|
this.argumentExpressionHandler = argumentExpressionHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassExpression visitReferenceExpression(final ReferenceExpressionContext ctx) {
|
||||||
|
return new ReferenceJassExpression(ctx.ID().getText());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassExpression visitParentheticalExpression(final ParentheticalExpressionContext ctx) {
|
||||||
|
return visit(ctx.expression());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassExpression visitStringLiteralExpression(final StringLiteralExpressionContext ctx) {
|
||||||
|
final String stringLiteralText = ctx.STRING_LITERAL().getText();
|
||||||
|
return new LiteralJassExpression(
|
||||||
|
new StringJassValue(stringLiteralText.substring(1, stringLiteralText.length() - 1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassExpression visitIntegerLiteralExpression(final IntegerLiteralExpressionContext ctx) {
|
||||||
|
return new LiteralJassExpression(new IntegerJassValue(Integer.parseInt(ctx.INTEGER().getText())));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassExpression visitFunctionReferenceExpression(final FunctionReferenceExpressionContext ctx) {
|
||||||
|
return new FunctionReferenceJassExpression(ctx.ID().getText());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassExpression visitArrayReferenceExpression(final ArrayReferenceExpressionContext ctx) {
|
||||||
|
return new ArrayRefJassExpression(ctx.ID().getText(), visit(ctx.expression()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassExpression visitFalseExpression(final FalseExpressionContext ctx) {
|
||||||
|
return new LiteralJassExpression(new BooleanJassValue(false));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassExpression visitTrueExpression(final TrueExpressionContext ctx) {
|
||||||
|
return new LiteralJassExpression(new BooleanJassValue(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassExpression visitFunctionCallExpression(final FunctionCallExpressionContext ctx) {
|
||||||
|
return new FunctionCallJassExpression(ctx.functionExpression().ID().getText(),
|
||||||
|
argumentExpressionHandler.argumentsVisitor.visit(ctx.functionExpression().argsList()));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,49 @@
|
|||||||
|
package com.etheller.interpreter.ast.visitors;
|
||||||
|
|
||||||
|
import com.etheller.interpreter.JassBaseVisitor;
|
||||||
|
import com.etheller.interpreter.JassParser.BasicGlobalContext;
|
||||||
|
import com.etheller.interpreter.JassParser.DefinitionGlobalContext;
|
||||||
|
import com.etheller.interpreter.ast.scope.GlobalScope;
|
||||||
|
import com.etheller.interpreter.ast.scope.LocalScope;
|
||||||
|
import com.etheller.interpreter.ast.value.JassType;
|
||||||
|
import com.etheller.interpreter.ast.value.PrimitiveJassType;
|
||||||
|
import com.etheller.interpreter.ast.value.visitor.ArrayPrimitiveTypeVisitor;
|
||||||
|
|
||||||
|
public class JassGlobalsVisitor extends JassBaseVisitor<Void> {
|
||||||
|
private static final LocalScope EMPTY_LOCAL_SCOPE = new LocalScope();
|
||||||
|
private final GlobalScope globals;
|
||||||
|
private final JassTypeVisitor jassTypeVisitor;
|
||||||
|
private final JassExpressionVisitor jassExpressionVisitor;
|
||||||
|
|
||||||
|
public JassGlobalsVisitor(final GlobalScope globals, final JassTypeVisitor jassTypeVisitor,
|
||||||
|
final JassExpressionVisitor jassExpressionVisitor) {
|
||||||
|
this.globals = globals;
|
||||||
|
this.jassTypeVisitor = jassTypeVisitor;
|
||||||
|
this.jassExpressionVisitor = jassExpressionVisitor;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Void visitBasicGlobal(final BasicGlobalContext ctx) {
|
||||||
|
final JassType type = jassTypeVisitor.visit(ctx.type());
|
||||||
|
final PrimitiveJassType arrayPrimType = type.visit(ArrayPrimitiveTypeVisitor.getInstance());
|
||||||
|
if (arrayPrimType != null) {
|
||||||
|
globals.createGlobalArray(ctx.ID().getText(), type);
|
||||||
|
} else {
|
||||||
|
globals.createGlobal(ctx.ID().getText(), type);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Void visitDefinitionGlobal(final DefinitionGlobalContext ctx) {
|
||||||
|
final JassType type = jassTypeVisitor.visit(ctx.type());
|
||||||
|
final PrimitiveJassType arrayPrimType = type.visit(ArrayPrimitiveTypeVisitor.getInstance());
|
||||||
|
if (arrayPrimType != null) {
|
||||||
|
globals.createGlobalArray(ctx.ID().getText(), type);
|
||||||
|
} else {
|
||||||
|
globals.createGlobal(ctx.ID().getText(), type,
|
||||||
|
jassExpressionVisitor.visit(ctx.assignTail().expression()).evaluate(globals, EMPTY_LOCAL_SCOPE));
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,38 @@
|
|||||||
|
package com.etheller.interpreter.ast.visitors;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.etheller.interpreter.JassBaseVisitor;
|
||||||
|
import com.etheller.interpreter.JassParser.ListParameterContext;
|
||||||
|
import com.etheller.interpreter.JassParser.NothingParameterContext;
|
||||||
|
import com.etheller.interpreter.JassParser.SingleParameterContext;
|
||||||
|
import com.etheller.interpreter.ast.function.JassParameter;
|
||||||
|
|
||||||
|
public class JassParametersVisitor extends JassBaseVisitor<List<JassParameter>> {
|
||||||
|
private final JassTypeVisitor typeVisitor;
|
||||||
|
|
||||||
|
public JassParametersVisitor(final JassTypeVisitor typeVisitor) {
|
||||||
|
this.typeVisitor = typeVisitor;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<JassParameter> visitSingleParameter(final SingleParameterContext ctx) {
|
||||||
|
final List<JassParameter> list = new LinkedList<>();
|
||||||
|
list.add(new JassParameter(typeVisitor.visit(ctx.param().type()), ctx.param().ID().getText()));
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<JassParameter> visitListParameter(final ListParameterContext ctx) {
|
||||||
|
final List<JassParameter> list = visit(ctx.paramList());
|
||||||
|
list.add(0, new JassParameter(typeVisitor.visit(ctx.param().type()), ctx.param().ID().getText()));
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<JassParameter> visitNothingParameter(final NothingParameterContext ctx) {
|
||||||
|
return Collections.EMPTY_LIST;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,87 @@
|
|||||||
|
package com.etheller.interpreter.ast.visitors;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import com.etheller.interpreter.JassBaseVisitor;
|
||||||
|
import com.etheller.interpreter.JassParser.BlockContext;
|
||||||
|
import com.etheller.interpreter.JassParser.FunctionBlockContext;
|
||||||
|
import com.etheller.interpreter.JassParser.GlobalContext;
|
||||||
|
import com.etheller.interpreter.JassParser.ProgramContext;
|
||||||
|
import com.etheller.interpreter.JassParser.StatementContext;
|
||||||
|
import com.etheller.interpreter.JassParser.TypeDefinitionContext;
|
||||||
|
import com.etheller.interpreter.ast.function.JassFunction;
|
||||||
|
import com.etheller.interpreter.ast.function.JassNativeManager;
|
||||||
|
import com.etheller.interpreter.ast.function.UserJassFunction;
|
||||||
|
import com.etheller.interpreter.ast.scope.GlobalScope;
|
||||||
|
import com.etheller.interpreter.ast.statement.JassStatement;
|
||||||
|
|
||||||
|
public class JassProgramVisitor extends JassBaseVisitor<Void> {
|
||||||
|
private final GlobalScope globals = new GlobalScope();
|
||||||
|
private final JassNativeManager jassNativeManager = new JassNativeManager();
|
||||||
|
private final Map<String, String> typeToSuperType = new HashMap<>();
|
||||||
|
private final JassTypeVisitor jassTypeVisitor = new JassTypeVisitor(this.globals);
|
||||||
|
private final ArgumentExpressionHandler argumentExpressionHandler = new ArgumentExpressionHandler();
|
||||||
|
private final JassExpressionVisitor jassExpressionVisitor = new JassExpressionVisitor(
|
||||||
|
this.argumentExpressionHandler);
|
||||||
|
private final JassArgumentsVisitor jassArgumentsVisitor = new JassArgumentsVisitor(this.argumentExpressionHandler);
|
||||||
|
{
|
||||||
|
this.argumentExpressionHandler.setJassArgumentsVisitor(this.jassArgumentsVisitor);
|
||||||
|
this.argumentExpressionHandler.setJassExpressionVisitor(this.jassExpressionVisitor);
|
||||||
|
}
|
||||||
|
private final JassGlobalsVisitor jassGlobalsVisitor = new JassGlobalsVisitor(this.globals, this.jassTypeVisitor,
|
||||||
|
this.jassExpressionVisitor);
|
||||||
|
private final JassParametersVisitor jassParametersVisitor = new JassParametersVisitor(this.jassTypeVisitor);
|
||||||
|
private final JassStatementVisitor jassStatementVisitor = new JassStatementVisitor(this.argumentExpressionHandler);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Void visitBlock(final BlockContext ctx) {
|
||||||
|
if (ctx.globalsBlock() != null) {
|
||||||
|
for (final GlobalContext globalContext : ctx.globalsBlock().global()) {
|
||||||
|
this.jassGlobalsVisitor.visit(globalContext);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (ctx.nativeBlock() != null) {
|
||||||
|
this.jassNativeManager.registerNativeCode(ctx.nativeBlock().ID().getText(),
|
||||||
|
this.jassParametersVisitor.visit(ctx.nativeBlock().paramList()),
|
||||||
|
this.jassTypeVisitor.visit(ctx.nativeBlock().type()), this.globals);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Void visitProgram(final ProgramContext ctx) {
|
||||||
|
for (final TypeDefinitionContext typeDefinitionContext : ctx.typeDefinitionBlock().typeDefinition()) {
|
||||||
|
this.typeToSuperType.put(typeDefinitionContext.ID(0).getText(), typeDefinitionContext.ID(1).getText());
|
||||||
|
}
|
||||||
|
for (final BlockContext blockContext : ctx.block()) {
|
||||||
|
visit(blockContext);
|
||||||
|
}
|
||||||
|
for (final FunctionBlockContext functionBlockContext : ctx.functionBlock()) {
|
||||||
|
final List<JassStatement> statements = new ArrayList<>();
|
||||||
|
for (final StatementContext statementContext : functionBlockContext.statement()) {
|
||||||
|
statements.add(this.jassStatementVisitor.visit(statementContext));
|
||||||
|
}
|
||||||
|
final UserJassFunction userJassFunction = new UserJassFunction(statements,
|
||||||
|
this.jassParametersVisitor.visit(functionBlockContext.paramList()),
|
||||||
|
this.jassTypeVisitor.visit(functionBlockContext.type()));
|
||||||
|
this.globals.defineFunction(functionBlockContext.ID().getText(), userJassFunction);
|
||||||
|
}
|
||||||
|
final JassFunction mainFunction = this.globals.getFunctionByName("main");
|
||||||
|
if (mainFunction != null) {
|
||||||
|
mainFunction.call(Collections.EMPTY_LIST, this.globals);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GlobalScope getGlobals() {
|
||||||
|
return this.globals;
|
||||||
|
}
|
||||||
|
|
||||||
|
public JassNativeManager getJassNativeManager() {
|
||||||
|
return this.jassNativeManager;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,44 @@
|
|||||||
|
package com.etheller.interpreter.ast.visitors;
|
||||||
|
|
||||||
|
import com.etheller.interpreter.JassBaseVisitor;
|
||||||
|
import com.etheller.interpreter.JassParser.ArrayedAssignmentStatementContext;
|
||||||
|
import com.etheller.interpreter.JassParser.CallStatementContext;
|
||||||
|
import com.etheller.interpreter.JassParser.ReturnStatementContext;
|
||||||
|
import com.etheller.interpreter.JassParser.SetStatementContext;
|
||||||
|
import com.etheller.interpreter.ast.statement.JassArrayedAssignmentStatement;
|
||||||
|
import com.etheller.interpreter.ast.statement.JassCallStatement;
|
||||||
|
import com.etheller.interpreter.ast.statement.JassReturnStatement;
|
||||||
|
import com.etheller.interpreter.ast.statement.JassSetStatement;
|
||||||
|
import com.etheller.interpreter.ast.statement.JassStatement;
|
||||||
|
|
||||||
|
public class JassStatementVisitor extends JassBaseVisitor<JassStatement> {
|
||||||
|
private final ArgumentExpressionHandler argumentExpressionHandler;
|
||||||
|
|
||||||
|
public JassStatementVisitor(final ArgumentExpressionHandler argumentExpressionHandler) {
|
||||||
|
this.argumentExpressionHandler = argumentExpressionHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassStatement visitCallStatement(final CallStatementContext ctx) {
|
||||||
|
return new JassCallStatement(ctx.functionExpression().ID().getText(),
|
||||||
|
argumentExpressionHandler.argumentsVisitor.visit(ctx.functionExpression().argsList()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassStatement visitSetStatement(final SetStatementContext ctx) {
|
||||||
|
return new JassSetStatement(ctx.ID().getText(),
|
||||||
|
argumentExpressionHandler.expressionVisitor.visit(ctx.expression()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassStatement visitReturnStatement(final ReturnStatementContext ctx) {
|
||||||
|
return new JassReturnStatement(argumentExpressionHandler.expressionVisitor.visit(ctx.expression()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassStatement visitArrayedAssignmentStatement(final ArrayedAssignmentStatementContext ctx) {
|
||||||
|
return new JassArrayedAssignmentStatement(ctx.ID().getText(),
|
||||||
|
argumentExpressionHandler.expressionVisitor.visit(ctx.expression(0)),
|
||||||
|
argumentExpressionHandler.expressionVisitor.visit(ctx.expression(1)));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
package com.etheller.interpreter.ast.visitors;
|
||||||
|
|
||||||
|
import com.etheller.interpreter.JassBaseVisitor;
|
||||||
|
import com.etheller.interpreter.JassParser.ArrayTypeContext;
|
||||||
|
import com.etheller.interpreter.JassParser.BasicTypeContext;
|
||||||
|
import com.etheller.interpreter.JassParser.NothingTypeContext;
|
||||||
|
import com.etheller.interpreter.ast.scope.GlobalScope;
|
||||||
|
import com.etheller.interpreter.ast.value.JassType;
|
||||||
|
|
||||||
|
public class JassTypeVisitor extends JassBaseVisitor<JassType> {
|
||||||
|
private final GlobalScope globals;
|
||||||
|
|
||||||
|
public JassTypeVisitor(final GlobalScope globals) {
|
||||||
|
this.globals = globals;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassType visitArrayType(final ArrayTypeContext ctx) {
|
||||||
|
return globals.parseArrayType(ctx.ID().getText());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassType visitBasicType(final BasicTypeContext ctx) {
|
||||||
|
return globals.parseType(ctx.ID().getText());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JassType visitNothingType(final NothingTypeContext ctx) {
|
||||||
|
return JassType.NOTHING;
|
||||||
|
}
|
||||||
|
}
|
@ -1 +1 @@
|
|||||||
include 'desktop', 'core', 'fdfparser'
|
include 'desktop', 'core', 'fdfparser', 'jassparser'
|
Loading…
Reference in New Issue
Block a user